Java 8 New Features
Java 8 New Features
JavaFX is a set of graphics and media packages that enables developers to design, create, test, debug,
and deploy rich client applications that operate consistently across diverse platforms.
- Lambda expressions
A lambda expression is an anonymous function. A function that doesn’t have a name and doesn’t belong
to any class.
//Syntax of lambda expression
(parameter_list) -> {function_body}
(x, y) -> x + y lambda expression takes two arguments x and y and returns the sum of these
Functional interface = An interface with only single abstract method (exemple: Runnable, callable,
ActionListener etc).
To use lambda expression, you need to either create your own functional interface or use the pre-
defined functional interface provided by Java
Pre Java 8:
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
System.out.println("Hello World!");
}
});
Post Java 8:
b.addActionListener(e -> System.out.println("Hello World!"));
Exemplu 1: Java Lambda Expression with no parameter
@FunctionalInterface
interface MyFunctionalInterface {
// lambda expression
MyFunctionalInterface msg = () -> {
return "Hello";
};
System.out.println(msg.sayHello());
- Method references
Method reference is a shorthand notation of a lambda expression to call a method
The :: operator is used in method reference to separate the class or object from the method name
Interface BiFunction<T,U,R>
Type Parameters:
import java.util.function.BiFunction;
class Multiplication{
public static int multiply(int a, int b){
return a*b;
}
}
Arrays.sort(stringArray, String::compareToIgnoreCase);
Old way:
String[] names = { "Steve", "Rick", "Aditya"};
The functional interface should have Only one abstract method. Along with the one abstract method,
they can have any number of default and static methods.
To use lambda expression in Java, you need to either create your own functional interface or use the pre
defined functional interface provided by Java
// lambda expression
MyFunctionalInterface sum = (a, b) -> a + b;
System.out.println("Result: "+sum.addMethod(12, 100));
}
}
// lambda expression
IntBinaryOperator sum = (a, b) -> a + b;
System.out.println("Result: " + sum.applyAsInt(12, 100));
}
}
The reason we have default methods in interfaces is to allow the developers to add new methods to the
interfaces without affecting the classes that implements these interfaces.
Reason:
If we add a new method to the XYZInterface, we have to change the code in all the classes that
implements the interface. Maybe we talk about hundreds of classes.
Static methods in interfaces are similar to the default methods except that we cannot override these
methods in the classes that implements these interfaces.
}
}
Since these methods are static, we cannot override them in the implementation classes.
Similar to default methods, we need to implement these methods in
implementation classes so we can safely add them to the existing interfaces.
!!! Nu am inteles cele 2. Nu se bat cap in cap?
interface MyInterface{
default void newMethod(){
System.out.println("Newly added default method");
}
Now the differences between interfaces and abstract classes: abstract class can have constructor while
in interfaces we can’t have constructors.
The multiple inheritance problem can occur, when we have two interfaces with the default methods of
same signature.
interface MyInterface{
To solve this problem, we can implement this method in the implementation class like this:
public class Example implements MyInterface, MyInterface2{
/ /Implementation of duplicate default method
public void newMethod(){
System.out.println("Implementation of default method");
}
Stream API
By using streams we can perform various aggregate operations on the data returned from collections,
arrays, Input/Output operations
List<String> names = new ArrayList<String>();
names.add("Ajeet");
names.add("Negan");
names.add("Aditya");
names.add("Steve");
//Old style
int count = 0;
for (String str : names) {
if (str.length() < 6)
count++;
}
In the second example, the stream() method returns a stream of all the names, the filter() method
returns another stream of names with length less than 6, the count() method reduces this stream to the
result. All these operations are happening parallelly which means we are able to parallelize the code
with the help of streams. Parallel execution of operations using stream is faster than sequential
execution without using streams.
1. Create a stream
2. Perform intermediate operations on the initial stream to transform it into another
3. Perform terminal operation
2. The aggregate operations that we perform on the collection, array, or any data source do not
change the data of the source.
3. All the stream operations are lazy - they are not executed until they are needed.
//creating two streams from the two lists and concatenating them into one
Stream<String> opstream = Stream.concat(alphabets.stream(), names.stream());
//displaying the elements of the concatenated stream
opstream.forEach(str->System.out.print(str+" "));
Stream Filter
The filter() is an intermediate operation that reads the data from a stream and returns a new stream
after transforming the data based on the given condition.
List<String> names = Arrays.asList("Melisandre","Sansa”);
.filter(str -> str.length() > 6) //filter the stream to create a new stream
longnames.forEach(System.out::println);
.collect(Collectors.toList());
forEach
forEach method to iterate over collections and Streams.
hmap.forEach((key,value)->System.out.println(key+" - "+value));
hmap.forEach((key,value)->{
if(key == 4
|| "Cat".equals(value)) { System.out.println(value); }
});
Stream forEachOrdered()
when working with parallel streams, you would always want to use the forEachOrdered() method when
the order matters to you, as this method guarantees that the order of elements would be same as the
source
names.stream()
.filter(f->f.startsWith("M"))
.parallel()
.forEachOrdered(n->System.out.println(n));
StringJoiner
class StringJoiner
Using this class we can join more than one strings with the specified delimiter, we can also provide
prefix and suffix to the final string while joining multiple strings.
Output: Logan-Magneto
Output: (Negan,Rick)
mystring.add("Negan");
mystring.add("Rick");
System.out.println("First String: "+mystring);
myanotherstring.add("Sansa");
myanotherstring.add("Imp");
Optional Class
Optional class in java.util package. This class is introduced to avoid NullPointerException that we
frequently encounters if we do not perform null checks in our code.
Old style:
String[] str = new String[10];
//Getting the substring
String str2 = str[9].substring(2, 5);
System.out.print(str2);
Output:
Exception in thread "main" java.lang.NullPointerException
at Example.main(Example.java:5)
Optional.ofNullable() method of the Optional class, returns a Non-empty Optional if the given
object has a value, otherwise it returns an empty Optional.
by using isPresent() method we can check whether the particular Optional object(or instance) is
empty or no-empty.
1.The given array is divided into the sub arrays and the sub arrays are further divided into
the their sub arrays, this happens until the sub array reaches a minimum granularity.
2. The sub arrays are sorted individually by multiple threads. The parallel sort uses Fork/Join
Framework for sorting sub arrays parallelly.
3. The sorted sub arrays are merged
The parallelSort() method uses the concept of multithreading which makes it much faster compared to
the normal sort when there are lot of elements.
Output: 1 5 19 22 32 89