The target of this article is to show some features of Java 8 by example. In special, the features of Stream API, Lambda Expressions, and Functional Interfaces.
What is a Functional Interface?
An interface with Single abstract method is called as Functional interface.
Types of Functional Interface’s:
Mainly there are 4 functional interface types.
- Supplier:
- Consumer
- Predicate
- Function
Supplier:
@FunctionalInterface
public interface Supplier<T> {
T get();
}Consumer:
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}Examples:
x -> System.out.println(x) // System.out::println
x -> x.doSomething()Predicate:
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}Examples:
x -> x.isDirectory() // File::isDirectory
x -> x % 2 == 0
Function:
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}Examples:
x -> x.length() // File::length
x -> x.getId()
FUNCTIONAL INTERFACE | PARAMETER TYPES | RETURN TYPE | DESCRIPTION |
Supplier<T> | NONE | T | Supplies a value of type T |
Consumer<T> | T | void | Consumes a value of type T |
Predicate<T> | T | boolean | A boolean-valued function |
Function<T, R> | T | R | A function with argument T and return R |
ToIntFunction<T> | T | int | An int-valued function |
ToLongFunction<T> | T | long | A long-valued function |
ToDoubleFunction<T> | T | double | A double-valued function |
IntFunction<R> | int | R | A function with argument of type int |
LongFunction<R> | long | R | A function with argument of type long |
DoubleFunction<R> | double | R | A function with argument of type double |
UnaryOperator<T> | T | T | A unary operator of type T |
Functional Interface and Lambda Expressions
Given a method that takes a functional interface as parameter:
public abstract class AbstractButton extends JComponent implements ItemSelectable, SwingConstants { /* ... */ public void addActionListener(ActionListener l) { /* ... */ } /* ... */ }
And a functional interface:
public interface ActionListener extends EventListener {
void actionPerformed(ActionEvent e);
}
You can code in the old-fashioned way using an anonymous class:
JButton button = new JButton("DON'T PANIC"); button.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println(e); } } );
Or you can code in a new way using a lambda expressions:
JButton button = new JButton(“DON’T PANIC”);
// LAMBDA EXPRESSION
button.addActionListener(e -> System.out.println(e));
Or even more concise using a method reference:
JButton button = new JButton(“DON’T PANIC”);
// LAMBDA EXPRESSION WITH METHOD REFERENCE
button.addActionListener(System.out::println);
Method Reference:
object::instanceMethod
Class::instanceMethod
Class::staticMethod
Constructor Reference:
Class::new
Streams:
- All in one package: java.util.stream
- Supports functional-style operations
- All stream operations take lambda expressions as arguments
- Integrated into the Collections API (but streams are not collections)
- Enables bulk operations on collections through convenient methods
- Enables filter and map-reduce transformations
- Enables lazy evaluation and short-circuit operations
- Never modify the underlying data structure
- Supports infinite (unbounded) streams
- Supports parallel execution
Working With Streams:
- Create streams from collections, arrays, generators or iterators
- Collect streams results in collections, arrays, strings, or maps
- Work with null values using Optional type
- Use specialized streams for primitive types
- Use filter operation to select
- Use map operation to transform
Pipeline of Operations:
- Create a stream
- Specify intermediate operations (for transforming the initial stream into others)
- Apply a terminal operation to produce a result