Java8
- megha dureja
- May 4, 2020
- 2 min read
Updated: Jun 6, 2020
Java 8 is here, offers exciting new possibilities for functional programming. While lambdas are the most prominent addition to Java 8, there are many other new features, such as functional interfaces, virtual methods, class and method references, new time and date API, JavaScript support, and so on.

"a non-abstract method implementations to interfaces by utilizing the default keyword is known as Default / Extension Methods."
interface Formula {
double calculate(int a);
default double sqrt(int a) {
return Math.sqrt(a);
}
}
Besides the abstract method calculate the interface Formula also defines the default method sqrt. Concrete classes only have to implement the abstract method calculate. The default method sqrt can be used out of the box.
Formula formula = new Formula() {
@Override
public double calculate(int a) {
return sqrt(a * 100);
}
};
formula.calculate(100); // 100.0
formula.sqrt(16); // 4.0
The formula is implemented as an anonymous object.
Default Methods enable you to add new functionality to the interfaces of your libraries and ensure binary compatibility with code written for older versions of those interfaces.
Rules around Default Methods are:-
The default method must have a body
Implementation classes are not required to override a default method
We can have 0 or N default methods in an interface
"A function which can be created without belonging to any class becomes Lambda expression."
It is commonly used to implement simple event listeners / callbacks, functional interfaces or in functional programming with the Java Streams API.
Syntax
(argument-list) -> {body}
Java lambda expression is consisted of three components.
1) Argument-list: It can be empty or non-empty as well.
2) Arrow-token: It is used to link arguments-list and body of expression.
3) Body: It contains expressions and statements for lambda expression.
"An interface with exactly one abstract method becomes Functional Interface."
Examples of java8 functional interfaces:-
Predicate accepts an argument and returns a boolean. Usually, it used to apply in a filter for a collection of objects.
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
Predicate<String> p1 = String::isEmpty;
System.out.println(p1.test(""));
Predicate<String> p2 = x-> x.isEmpty(); //true
System.out.println(p2.test("") ); //true
BiPredicate accepts two arguments and returns a boolean, basically this BiPredicate is same with the Predicate, instead, it takes 2 arguments for the test.
@FunctionalInterface
public interface BiPredicate<T, U> {
boolean test(T t, U u);
}
BiPredicate<String, String> b1 = String::startsWith;
BiPredicate<String, String> b2 = (string,prefix) -> string.endsWith(prefix);
System.out.println(b1.test("Java", "J") ); //true
System.out.println(b2.test("Java", "A") ); //false
Consumer takes an argument and returns nothing.
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
Consumer<String> print = x -> System.out.println(x);
print.accept("java"); // java
BiConsumer takes two arguments and returns nothing.
@FunctionalInterface
public interface BiConsumer<T, U> {
void accept(T t, U u);
}
BiConsumer<Integer, Integer> addTwo = (x, y) -> System.out.println(x + y);
addTwo.accept(1, 2); // 3
Comments