0% found this document useful (0 votes)
22 views

java 11 beyond basics

Uploaded by

Shriya Soni
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
22 views

java 11 beyond basics

Uploaded by

Shriya Soni
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 14

Why java 11 beyond

designed to enhance your knowledge of the Java 11 concepts.

through the advanced concepts in Java along with the usage of different tools in the development of
an enterprise application such as logging, testing, etc.

func:

work with Higher-Order functions like Lambdas and Streams which will simplify most of your
business logic by the size and complexity. Scores of lines will get reduced to fewer lines, the code as a
whole will become readable and the modularity also increases.

Lambda expressions

Use of @FunctionalInterface annotation(major requirement for any interface)

there should be only one abstract method in it. But an interface can contain more than one abstract
method, to make sure that not more than one abstract methods exist inside a functional interface

@FunctionalInterface is optional if the interface contains only one abstract method.

Lambda expressions should be short, concise, and clean.

//Better way to use @Functional Interface

@FunctionalInterface

interface MyInterface {

void add(int num1, int num2);

Avoid parameter types while defining Lambda expressions

(int num1, int num2) -> System.out.println(num1+ " " +num2); // Bad practice

//A parameter type is optional which can be avoided.

(num1, num2) -> System.out.println(num1+ " " +num2); // Good practice

Braces{} and Return statement are optional in one-line Lambda expressions

str -> { return str.toUpperCase(); } // Bad practice

str -> str.toUpperCase(); // Good practice


Avoid writing blocks of code in lambda expressions

good practice to not use lambda expressions whenever a large block of code has to be executed.

Prefer using Method references

str -> str.toUpperCase(); // Bad practice

String::toUpperCase; // Good practice

Streams: both serially and parallelly executable.

A Stream represents a sequence of elements from a source and supports various data processing
operations

provides an abstraction over an existing collection.

provide the support to parallel threading of the code, which breaks the bigger problem into smaller
chunks. These smaller problems are solved separately and their solutions are combined together to
obtain the final solution.

Concept of Functional Programming: Functions that can either accept other functions as parameters
or return other functions as parameters are called Higher Order Functions (HOF).

Higher-Order Functions can be either User-Defined or Inbuilt. Inbuilt Higher-Order Functions are
available through Streams in Java 8 and onwards.

create Built-In Streams in Java.

Creating a Stream from a Collection using stream() method.

List<String> castList = List.of("Sam","Dean","Castiel","Crowley");

Stream<String> supernatural = castList.stream();

Creating a Stream from an Array using stream() method.

Integer[] array = {672, 340, 999};

Stream<Integer> stream = Arrays.stream(array);


Creating a Stream directly using of() method.

1. Creating a Stream directly for Integers:

Stream<Integer> stream = Stream.of(672, 340, 999);

2. a Stream directly for Objects of User-Defined Classes:

//User Defined Class Employee

class Employee{

private String name;

private Double salary;

public Employee(String name, Double salary) {

super();

this.name = name;

this.salary = salary;

//Creating a Stream for objects of Class Employee

Stream<Employee> empStream = Stream.of( new Employee("Tom",5699.5), new


Employee("Jack",7629.2),new Employee("Jane",5289.8));

different operations that can be done on Streams are:

1. forEach(): traverse each element of stream . Used to display


the elements.

List<String> placesToVisit= new ArrayList<String>();


placesToVisit.add("Chicago");
placesToVisit.add("Venice");
placesToVisit.add("Tokyo");
placesToVisit.add("San Francisco");
placesToVisit.add("Kyoto");
placesToVisit.add("Abu Dhabi");
placesToVisit.forEach(place -> System.out.println("Trip to " + place));
2. map(): used to return a new stream based on operations done on an existing stream.

List<String> placesToVisit= new ArrayList<String>();

placesToVisit.add("Chicago");

placesToVisit.add("Venice");

placesToVisit.add("Tokyo");

placesToVisit.add("San Francisco");

placesToVisit.add("Kyoto");

placesToVisit.add("Abu Dhabi");

placesToVisit.stream().map(place -> place.toUpperCase()).forEach(place ->


System.out.println(place));

3. filter(): used to return a new filtered stream based on conditions given for filtering

List<String> placesToVisit= new ArrayList<String>();

placesToVisit.add("Chicago");

placesToVisit.add("Venice");

placesToVisit.add("Tokyo");

placesToVisit.add("San Francisco");

placesToVisit.add("Kyoto");

placesToVisit.add("Abu Dhabi");

placesToVisit.stream().filter(place -> place.length() == 5).forEach(x -> System.out.println(x));

4. sorted(): used to sort the elements in a Stream. Argument for this method is optional.

//No Argument passed in sorted()

List<String> placesToVisit= new ArrayList<String>();

placesToVisit.add("Chicago");

placesToVisit.add("Venice");

placesToVisit.add("Tokyo");

placesToVisit.add("San Francisco");

placesToVisit.add("Kyoto");

placesToVisit.add("Abu Dhabi");

placesToVisit.stream().sorted().forEach(x -> System.out.println(x));


//Lambda Expression passed as Argument in sorted()

List<String> placesToVisit= new ArrayList<String>();

placesToVisit.add("Chicago");

placesToVisit.add("Venice");

placesToVisit.add("Tokyo");

placesToVisit.add("San Francisco");

placesToVisit.add("Kyoto");

placesToVisit.add("Abu Dhabi");

placesToVisit.stream().sorted((str1,str2) -> str1.compareTo(str2)).forEach(x -> System.out.println(x));

5. Collect(): stores the modified stream as a new collection type (it can be list, map etc.)

List<Integer> number = new ArrayList();

number.add(2);

number.add(3);

number.add(4);

number.add(5);

//The Modified Stream is stored in "doubled" using collect()

List<Integer> doubled = number.stream().map(x->2*x).collect(Collectors.toList());

System.out.println(doubled);
different operations of Stream individually:

List<String> placesToVisit= new ArrayList<String>();

placesToVisit.add("Chicago");

placesToVisit.add("Venice");

placesToVisit.add("Tokyo");

placesToVisit.add("San Francisco");

placesToVisit.add("Kyoto");

placesToVisit.add("Abu Dhabi");

//stream() converts the List into a Stream

Stream<String> streamPlaces = placesToVisit.stream();

//filter() applies the appropriate filter conditions to obtain Modified Stream

Stream<String> filterStream = streamPlaces.filter(place -> place.length() <= 8);

//map() applies appropriate modification to a given Stream

Stream<String> mapFilter = filterStream.map(place -> place.toUpperCase());

//forEach() displays all the content of the Stream in console

mapFilter.forEach(x -> System.out.println(x));

short by chaining all the separate methods together

List<String> placesToVisit= new ArrayList<String>();

placesToVisit.add("Chicago");

placesToVisit.add("Venice");

placesToVisit.add("Tokyo");

placesToVisit.add("San Francisco");

placesToVisit.add("Kyoto");

placesToVisit.add("Abu Dhabi");

//Chaining Multiple Operations of Streams Together

placesToVisit.stream() //stream()

.filter(place -> place.length() <= 8) //filter()

.map(place -> place.toUpperCase()) //map()

.forEach(x -> System.out.println(x)); //forEach()


Streams follow a pipeline format of execution. All the operations that are chained together form the
intermediate operations. The last operation, after which the final result is obtained, forms the
terminal operation. All the intermediate operations are executed simultaneously based on the
stream and the required conditions.

Operations such as map(), filter(), sorted() comprise the intermediate operations, intermediate
operations return a stream after its execution.

Operations such as forEach() and/or collect() comprise the terminal operations, as these operations
do not return any stream, they deliver the final stream by either by displaying them (forEach()) or by
storing them in a collection (collect()).

Problem Statement

Stream of random integers. Our goal is to display a sorted stream consisting of cubes of all even
integers in the given stream. We have the following chained stream operations as our solution.

Stream<Integer> intStream = Stream.of(10,2,7,5,6,5,8,11);

intStream.filter(n -> { System.out.println("Filtering Current Element: "+n); return n % 2 == 0; })

.map(n -> { System.out.println("Mapping Current Element: "+n); return n * n * n; })

.sorted()

.forEach(n -> System.out.println(n));

This flow of execution can be visually represented as


Streams are lazy!!

because until the terminal operation is invoked, none of the intermediate operations is executed.

Non-Reusability of streams

a runtime exception will be thrown. This is because once a stream is operated on it cannot be
operated on once more.

properties file

Properties file is a text file used to store any kind of textual information in the form of key-value pairs

used for

1. storing configuration related data


2. storing information which can be changed frequently as unlike a Java class file, recompilation
is not needed if the information is changed from a properties file
3. containing locale-specific data. It internationalizes Java code by making the code locale-
dependent.

How to read a .properties file.

1. by using a third-party library called Apache Commons(provides classes that can be used to
perform certain operations on a ".properties" file. It contains a PropertiesConfiguration class
which is used to read a properties file).

Logging

Logging is the process of tracking the execution of the program where,

1. Any event that is to the interest of the programmer or administrator can be logged.
2. Relevant messages can be recorded in the event of exceptions and errors.

For the ease of the developer, there are many logging APIs available. Based on the requirement, the
developer can choose any of them. Few popular APIs for logging are,

1. JDK Logging API


2. Apache Log4J
3. Apache Commons Logging API

using the combination of Apache Commons Logging API and Apache Log4J.

Apache Commons Logging is a logging utility that is Java-based and provides the implementation of
loggers and also supports the different Logging APIs.

Log4j is written in Java and is open source. It provides mechanisms to directly log information to a
variety of destinations such as database, file, console, etc. It also logs information in various
formatting styles such as HTML, XML, Log, etc. We are using an updated version of Log4J, i.e., Log4j2.
Log4j2 has 3 components

1. Appender – Specifies where the logging output should be stored. It can be the console, an
external file, any database, etc.
2. Layout– Specifies in what format should the information be logged. It can be a simple layout
which logs the level followed by the message, or we can specify a pattern for it to follow, etc.
3. Logger – Accepts all the information to be logged and redirects it to an appropriate
Appender.

Logging Levels used to differentiate between the severity between different logs. Logging Levels are
provided by the class.

Testing using Junit5

Testing of single small units of code such as a method or a class and asserting certain behavior is
called unit testing. It is done by the person who develops the code.

Unit testing can be :

Manual

Which is time-consuming

Can be error prone

Automated

Which saves time

Useful for frequently changing code

Less error prone compared to manual testing

There are several frameworks available for automating unit tests. JUnit and TestNG are among the
popular ones.

JUnit
JUnit is an open-source unit testing framework for Java. It provides classes to write and run
automated tests.

It provides :

1. annotations to create and customize tests


2. a platform where common functionalities can be performed before or after the execution of
each test case/class
3. library functions which are used to define when a test case should pass or fail
4. platform to execute multiple test classes together

JUnit5

latest version of JUnit which was released in 2017.

JUnit Platform, is the project which helps in executing the tests on the Java Virtual Machine(JVM). It
also provides the definition for TestEngine API (which discovers test cases in a project and executes
them).

JUnit Jupiter is the main project which helps you write test cases in accordance to JUnit 5. It also
provides TestEngine definition for running Jupiter based test cases. (Note: The name for this came up
to being Jupiter, because, Jupiter is the only planet in our solar system whose name starts with 'J',
and also it is the 5th planet is our solar system, indicating the version of JUnit, ergo, JUnit 5.)

JUnit Vintage provides the definition for TestEngine that supports the previous versions of JUnit, like
JUnit 3 or JUnit 4.

JUnit is a testing framework to which the programmer specifies three things,

1. the method to be checked


2. the inputs provided to the method
3. the expected output

creation of a JUnit test case also involves the creation of a class.

Test cases in Java are nothing but regular methods.


To recognise a test case method, we have to use the annotation, @Test on the said method. This
@Test annotation will set our test case method apart from the regular methods of our project, thus
enabling the JUnit framework to recognise and execute it.

Without the annotation, neither can the JUnit Framework recognise the method, nor can it execute
it.

Since JUnit 5 has the support for JUnit 4, there will be two instances for @Test annotation. Please
import the annotation from org.junit.jupiter.api.Test. The other @Test which comes from
org.junit.Test creates test case methods for JUnit 4 Framework.

best part is the test case execution part.

Once you execute the test case, the JUnit framework will take over, call the method to be executed
and execute it. You will then be able to see an output.

To specify the output to the test case method, we will use a special class called Assertions (imported
from org.junit.jupiter.api.Assertions). This class provides various methods, using which we can
specify the expected output to the test case. Few of the important methods are,

assertEquals(Object expected, Object actuals) - This method accepts two parameters and passes the
test case only if both of the parameters are equal

assertNotEquals(Object expected, Object actuals) - This method accepts two parameters and passes
the test case only if both of the parameters are not equal

assertTrue(boolean condition) - This method accepts a boolean return condition and passes the test
case only if the return value is true.

assertFalse(boolean condition) - This method accepts a boolean return condition and passes the test
case only if the return value is false.

assertNull(Object actual) - This method accepts an object and passes the test case only if the object
is null.

assertNotNull(Object actual) - This method accepts an object and passes the test case only if the
object is not null.

Note: All the methods specified above are static.

To test for exceptions, Assertions class has a special method, assertThrows()

assertThrows(Class<Exception> expectedType, Executable executable) - This method accepts two


parameters, the first one the class of the exception that is expected and the second an
implementation of the Executable interface, which invokes the function to be tested. If the exception
that is thrown is not the same as the expected exception, the test case will fail. Else the test case will
pass and the assertion method will return the Exception object that it got from the tested method.

Note: Executable interface is a functional interface, which accepts no parameters and returns the
value returned by the invoked function. To implement the Executable interface, we will use a Lambda
function.
3.1 Assignment 1 – Problem Statement, Solution, Assessment, and Conclusion

Problem Statement: InfyAcademy requires assistance in adding candidates and generating their
performance reports. This assignment focuses on implementing the necessary modules to facilitate
these functionalities. The specific tasks include converting conditional and iterative statements to
ternary operators or stream functions and ensuring that exceptions are appropriately logged and
propagated.

Solution:

 InfyAcademyException: A user-defined exception to handle specific error scenarios within


the application.

 Validator Class: Implements various validation methods for candidate attributes, ensuring
that only valid data is processed.

o isValidCandidateName: Ensures the name contains only English letters.

o isValidCandidateId: Validates the ID has exactly five digits.

o isValidDepartment: Confirms the department is one of the predefined valid options.

4o

What are assignment 1,2,3 doing , difference between them and the function of it

ChatGPT

Chapter 3: ASSIGNMENTS AND ASSESSMENTS

3.1 Assignment 1 – Problem Statement, Solution, Assessment, and Conclusion

Problem Statement: InfyAcademy requires the development of modules to add candidates and
generate candidate reports. This assignment involves converting conditional and iterative statements
to ternary operators or stream functions, improving the efficiency and readability of the code.

Solution:

 InfyAcademyException: A user-defined exception to handle specific error scenarios.

 Validator Class: Implements various validation methods for candidate attributes.

o Convert conditional statements to ternary operators where applicable.

o Ensure logging and propagation of exceptions.

 CandidateServiceImpl Class: Implements business logic for adding candidates and


generating reports.

o Convert iterative statements to stream functions where applicable.

o Ensure logging and propagation of exceptions.

Function:

 Adding Candidates: Validate inputs and add valid candidates to the database.
 Generating Candidate Reports: Retrieve and process candidate data to generate reports.

3.2 Assignment 2 – Problem Statement, Solution, Assessment, and Conclusion

Problem Statement: This assignment focuses on enhancing the InfyAcademy application by


implementing logging for exceptions and ensuring proper exception propagation. Additionally, the
task includes writing JUnit test cases to validate the functionalities.

Solution:

 InfyAcademyException: Ensure proper logging and propagation of this user-defined


exception.

 Validator Class: Log all exceptions thrown by validation methods and propagate them.

 CandidateServiceImpl Class: Log exceptions thrown by service methods and propagate


them.

 CandidateServiceTest Class: Write JUnit test cases based on provided input-output


scenarios.

Function:

 Exception Handling: Implement logging and ensure exceptions are properly propagated.

 Testing: Validate the functionalities using JUnit test cases.

3.3 Assignment 3 – Problem Statement, Solution, Assessment, and Conclusion

Problem Statement: The third assignment involves rectifying bugs in the Validator and Service
classes and implementing detailed validation logic. The task also includes ensuring proper logging
and exception handling.

Solution:

 InfyAcademyException: Ensure proper construction and usage of this exception.

 Validator Class: Implement detailed validation logic for various candidate attributes.

o Validate candidate name, ID, department, exam date, exam marks, and result.

o Log exceptions and ensure they are propagated.

 CandidateServiceImpl Class: Implement business logic for adding candidates and calculating
grades.

o Validate inputs and handle incorrect results.

o Log exceptions and ensure they are propagated.

Function:

 Detailed Validation: Ensure all candidate attributes are validated according to specified
rules.

 Business Logic Implementation: Add candidates to the database and calculate grades based
on marks.
Differences and Functions

Differences:

1. Assignment 1:

o Focuses on converting conditional and iterative statements to ternary operators and


stream functions.

o Enhances code efficiency and readability.

2. Assignment 2:

o Emphasizes logging and proper exception handling.

o Involves writing JUnit test cases to validate functionalities.

3. Assignment 3:

o Focuses on detailed validation logic and bug fixing.

o Implements comprehensive business logic for adding candidates and generating


reports.

Functions:

1. Adding Candidates: Validate inputs and add valid candidates to the database.

2. Generating Candidate Reports: Retrieve and process candidate data to generate reports.

3. Exception Handling: Log and propagate exceptions to ensure robustness.

4. Testing: Validate functionalities using JUnit test cases.

5. Detailed Validation: Ensure all candidate attributes are validated according to specified
rules.

6. Business Logic Implementation: Add candidates to the database and calculate grades based
on marks.

You might also like