New Functional Features of Java 8
-
Upload
franciscoortin -
Category
Education
-
view
121 -
download
3
description
Transcript of New Functional Features of Java 8
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