new functional features of java 8

Post on 26-Jan-2015

123 Views

Category:

Education

3 Downloads

Preview:

Click to see full reader

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

top related