new functional features of java 8
DESCRIPTION
On March 2014, Java 8 was released. These informal slides describe the new elements of the programming languages, focusing on those taken from the functional paradigm.TRANSCRIPT
Software
Engineering
Computer Science
Engineering School
Francisco Ortin University of Oviedo
New Functional Features
of Java 8
Francisco Ortín Soler
Disclaimer
• This slides are aimed at briefly explaining the new functional features of Java 8
• It is an informal document
• The code used in this slides is available athttp://www.reflection.uniovi.es/download/2014/java8.zip
• It has been compiled and executed with Java SE Development Kit 8.0
March 20th, 2014
Francisco Ortin
ortin at lsi.uniovi.es
Francisco Ortín Soler
Java 8
• Java 8 has been released on March 2014
• It includes some features of the functional paradigm such as:
Lambda expressions
Method references
Types of some typical lambda expressions
Streams (aggregate operations)
Closures (constant variables of the enclosing block)
• It also provides default method implementations for interfaces
Francisco Ortín Soler
Lambda Expressions
• Lambda expressions are provided
The -> symbol separates parameters from body
Parameter types can be optionally specified
Parenthesis are not mandatory when only one parameter is passed
If the body is just one expression, return and { }are not required
String[] words = new String [] {
"Hello", "from", "Java", "8" };
Arrays.sort(words,
(word1, word2) -> word1.length() - word2.length()
);
Francisco Ortín Soler
Types of Lambda Expressions
• Lambda expressions promote to interfaces with one abstract method with the same signature as the lambda expression
• This kind of interfaces are called Functional Interfaces
The @FunctionalInterface annotation can be used
It is optional; helpful for detecting errors
@FunctionalInterface // not mandatory
interface MyPredicate<T> {
boolean exec(T element);
}
Francisco Ortín Soler
Types of Lambda Expressions
@FunctionalInterface // not mandatory
interface MyPredicate<T> {
boolean exec(T element);
}
class Promotion {
static <T> T find(T[] collection, MyPredicate<T> predicate) {
for(T item : collection)
if (predicate.exec(item))
return item;
return null;
}
public static void main(String... args) {
Integer[] numbers = new Integer [] { 1, 2, 3 };
int number = find(numbers, n -> n % 2 == 0);
System.out.println(number);
}
}
Francisco Ortín Soler
Method References
• Sometimes, a lambda expression does nothing but calling an existing method
• In those cases, the existing method can be referred by name
• For this purpose, the :: operator has been added to Java 8
• Static (class) methods are referred with Class::method
class MethodReferences {
static boolean isOdd(Integer number) {
return number %2 != 0;
}
public static void main(String... args) {
Integer[] numbers = new Integer [] { 1, 2, 3 };
Integer number = Promotion.find(numbers, MethodReferences::isOdd);
number = Promotion.find(numbers, new EqualTo(3)::compare);
}
}
Francisco Ortín Soler
Method References
• Instance methods are referred with object::method
• Since these methods are associated to an object (this), they can be stateful
class EqualTo {
private int value;
public EqualTo(int value) { this.value = value; }
public boolean compare(Integer n) { return value == n; }
}
public class MethodReferences {
public static void main(String... args) {
Integer[] numbers = new Integer [] { 1, 2, 3 };
Integer number = Promotion.find(numbers,
new EqualTo(3)::compare);
}
}
Francisco Ortín Soler
Types of Typical Lambda Exprs
• The package java.util.function provides types
(functional interfaces) of typical lambda functions
Function<T,R>: Function that receives a T argument and returns a R result
Predicate<T>: Predicate of one T argument
Consumer<T>: An operation that accepts a single Targument and returns no result
Supplier<T>: Function with no parameter returning a T value
UnaryOperator<T>: Operation on a single T operand, producing a T result
BinaryOperator<T>: Operation upon two Toperands, producing a result of the same type as the operands
Francisco Ortín Soler
Types of Typical Lambda Exprs
• Notice: the methods of the interfaces must be explicitly called, and they are named differently (test, accept, apply, get…)
public static void main(String... args) {
MyPredicate<Integer> even = n -> n%2 == 0; // my own type
Predicate<Integer> odd = n -> n%2 != 0;
System.out.println(even.exec(number) + " " + odd.test(number));
Consumer<Integer> printAction = n -> System.out.println(n);
printAction.accept(number);
Function<Integer,Double> sqrt = n -> Math.sqrt(n);
System.out.println(sqrt.apply(number));
Supplier<Integer> random = () -> (int)(Math.random()*1000 - 1000/2);
System.out.println(random.get());
BinaryOperator<Integer> times = (a,b) -> a*b;
System.out.printf(times.apply(3,2));
}
Francisco Ortín Soler
Types of Typical Lambda Exprs
• Since generics is implemented in Java with type erasure (i.e., T is Object), the previous types
have specific versions for built-in types:
And more…http://download.java.net/jdk8/docs/api/java/util/function/package-summary.html
Predicate<T> Supplier<T> Consumer<T> Function<T,R>
DoublePredicate BooleanSupplier DoubleConsumer DoubleFunction<R>
IntPredicate DoubleSupplier IntConsumer IntFunction<R>
LongPredicate IntSupplier LongConsumer IntToDoubleFunction
LongSupplier IntToLongFunction
LongFunction<R>
…
Francisco Ortín Soler
Streams with Aggregate Operations
• The new java.util.stream package provides an API to
support functional-style operations on streams
• A stream is a sequence of elements
It is not a data structure that stores elements (i.e. a collection)
• They support sequential and parallel functional-style aggregate operations
• Operations are composed into a stream pipeline
• Pipeline consists of
A source (array, collection, generator, I/O channel…)
Intermediate aggregate operations
And a terminal operation, producing a result
• Computation on the source data is only performed when the terminal operation is initiated (kind of lazy)
Francisco Ortín Soler
Streams (Aggregate Operations)
public class Streams {
static int compute(Collection<Integer> collection) {return collection.stream()
.filter(n -> n%2 == 0) // even numbers
.map(n -> n*n) // square
.reduce(0, (acc, item) -> acc + item); // summation}
public static void main(String... args) {System.out.println(compute(Arrays.asList(1, 2, 3, 4, 5)));
System.out.println(Arrays.asList(Stream.iterate(1, n -> n+1)
.skip(10)
.limit(5)
.toArray(Integer[]::new)));
}}
source
aggregate operations
terminal operation
source (infinite)
aggregate operations
terminal operation
• Similar to .NET LINQ
• There will be database streams eventually?
Francisco Ortín Soler
Closures
• Lambda expressions can capture variables of the enclosing scope
• They do not have shadowing issues (a new scope is not created, being lexically scoped)
• Captured variables must be final or effectively final (their value cannot be modified)
public class Closures {
static Function<Integer,Integer> createClosure(int initialValue) {
int number = initialValue; // must be constant
return n -> number + n;
}
public static void main(String... args) {
Function<Integer,Integer> closure1 = createClosure(1);
System.out.println(closure1.apply(7) );
Function<Integer,Integer> closure10 = createClosure(10);
System.out.println(closure10.apply(7) );
}
}
Francisco Ortín Soler
Closures
• Since functions are objects, they can represent functions with a mutable state
class Fibonacci implements Supplier<Integer> {
private int previous = 0, current = 1;
@Override
public Integer get() {
int next = current + previous;
previous = current;
current = next;
return previous;
}
public static void main(String... args) {
System.out.println(Arrays.asList(
Stream.generate(new Fibonacci()).limit(10)
.toArray(Integer[]::new)
));
}
}
Francisco Ortín Soler
Default Methods
• Java 8 provides default implementations for interface methods (the default keyword is used), similar to mixins
@FunctionalInterface interface Comparator<T> {
int compare(T a, T b);
default Comparator<T> reversed() { return (a, b) -> this.compare(b,a); }
}
public class DefaultMethods {
public static <T> T max(T a, T b, Comparator<T> comp) {
return comp.compare(a,b)<0 ? a : b;
}
public static <T> T min(T a, T b, Comparator<T> comp) {
return max(a, b, comp.reversed());
}
public static void main(String... args) {
Comparator<String> comparator = (a,b) -> a.length() - b.length();
System.out.println(max("hello", "bye", comparator));
System.out.println(min("hello", "bye", comparator));
} }
Francisco Ortín Soler
Multiple Inheritance
• As with multiple inheritance languages, different implementations of the same method may be inherited
• However, the Java compiler checks this condition, reporting an error
interface A {
default void m() { System.out.println("A::m"); }
}
interface B {
default void m() { System.out.println("B::m"); }
}
public class MultipleInheritance
implements A, B { // compiler error
}
Francisco Ortín Soler
Multiple Inheritance
• Besides, a default method cannot be inherited if the class implements another interface with that method (even without a default implementation)
interface A {
default void m() { System.out.println("A::m"); }
}
interface C {
void m();
}
class MyClass implements A, C { // compiler error
}
Francisco Ortín Soler
Multiple Inheritance
• Java 8 allows diamond inheritance: the most specific (derived) method implementation is called
interface A {
default void m() { System.out.println("A::m"); }
}
interface A1 extends A {}
interface A2 extends A {
default void m() { System.out.println("A2::m"); }
}
class Diamond implements A1, A2 {
public static void main(String... args) {
new Diamond().m(); // A2::m
A1 a1 = new Diamond();
a1.m();
} }
Francisco Ortín Soler
Static Methods
• Java 8 allows interfaces to implement static methods to provide utility methods
• The static methods specific to an interface can be kept in the same interface rather than in a separate class
@FunctionalInterface
interface Comparator<T> {
int compare(T a, T b);
static <T extends Comparable<T>> Comparator<T> naturalOrder() {
return (a,b) -> a.compareTo(b);
}
}
public class DefaultMethods {
public static void main(String... args) {
System.out.println(
max("hello", "bye", Comparator.naturalOrder()
));
} }
Software
Engineering
Computer Science
Engineering School
Francisco Ortin University of Oviedo
New Functional Features
of Java 8