java8-presentation



java8-presentation

0 4


java8-presentation

Slides about the new features of Java 8

On Github DDuarte / java8-presentation

Java 8

Love & Hate

By Duarte Duarte, Eduardo Martins, Miguel Marques and Ruben Cordeiro

(these slides: http://goo.gl/h3C9N5) ESOF/MIEIC/FEUP - 2013/2014

Timeline

  • JDK 1.0 (January, 1996)
  • JDK 1.1 (February, 1997)
  • J2SE 1.2 (December, 1998)
  • J2SE 1.3 (May, 2000)
  • J2SE 1.4 (February, 2002)
  • J2SE 5.0 (September, 2004)
  • Java SE 6 (December, 2006)
  • Java SE 7 (July, 2011)
  • Java SE 8 (March, 2014) [scheduled]

Lambdas

Anonymous methods aimed at reducing the verbosity caused by anonymous classes.

- Alonzo Church in his invention of the lambda calculus in 1936. - Lisp 1958 - Supported in C#, JavaScript, Python, Ruby, C++11

Lambdas

(int x, int y) -> x + y

() -> 42

(String s) -> { System.out.println(s); }
- Omission of brackets and return statement - Return type deduction

Lambdas

Examples

Before

JButton btn = new JButton();
final PrintStream pStream = ...;
btn.addActionListener(new ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        pStream.println("Button Clicked!");
    }
});

After

JButton btn = new JButton();
final PrintStream pStream = ...;
btn.addActionListener(e -> pStream.println("Button Clicked!"));
- Argument type deduction - In-place implementation. - Local variable capturing - Multiple lines lambdas

Lambdas

Examples

ArrayList<String> strs = ...;
Collections.sort(strs, (s1, s2) -> s2.length() - s1.length());
new Thread(() -> {
    connectToService();
    sendNotification();
}).start();

Functional Interfaces

Single Abstract Method Type

Functional Interfaces

Example

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

Runnable r = () -> System.out.println("Hello World!");
- @FunctionalInterface - May be omitted - Generates error when there is more than one abstract method - Attributing a lambda expression to a variable - Returning a lambda expression is also possible

java.util.function

  • Predicate<T> - a boolean-valued property of an object
  • Consumer<T> - an action to be performed on an object
  • Function<T, R> - a function transforming a T to a R
  • Supplier<T> - provide an instance of a T (such as a factory)
  • UnaryOperator<T> - a function from T to T
  • BinaryOperator<T> - a function from (T, T) to T- More meaningful type names

Method References

Treating an existing method as an instance of a Functional Interface

- Object oriented way of attributing a method to a variable

Method References

Examples

class Person {
    private String _name;
    private int _age;

    public int getAge() { return _age; }
    public String getName() { return _name; }
}

Person[] people = ...;
Comparator<Person> byName = Comparator.comparing(Person::getName);
Arrays.sort(people, byName);
- :: operator

Method References

Kinds of method references

  • A static method (ClassName::methName)
  • An instance method of a particular object (instanceRef::methName)
  • A super method of a particular object (super::methName)
  • An instance method of an arbitrary object of a particular type (ClassName::methName)
  • A class constructor reference (ClassName::new)
  • An array constructor reference (TypeName[]::new)- "Instance method of an arbitrary object" adds an argument of that type which becomes the receiver of the invocation

Method References

More Examples

Consumer<Integer> b1 = System::exit;
Consumer<String[]> b2 = Arrays::sort;
Consumer<String> b3 = MyProgram::main;
Runnable r = MyProgram::main;

Default Methods

Add default behaviours to interfaces

Why default methods?

Suppose Java 8 is out and has lambdas. We want to start using them:

List<?> list = ...
list.forEach(...); // lambda code goes here

There's a problem

The forEach method isn’t declared by java.util.list nor the java.util.collection interface yet.

Adding extra methods to the java.util.collection interfaces would break the existing implementations.

Default Methods

We have lambdas, but we can't force new behaviours into the current libraries.

Solution: default methods.

Default Methods

Default methods or defender methods, can now be added to interfaces providing a default implementation of the declared behavior.

Examples

Example 1

Basics

public interface A {

    default void foo() {
        System.out.println("Calling A.foo()");
    }
}

public class Clazz implements A {
}

Client code

Clazz clazz = new Clazz();
clazz.foo();

Output

"Calling A.foo()"

Example 2

Getting messy

public interface A {

    default void foo(){
        System.out.println("Calling A.foo()");
    }
}

public interface B {

    default void foo(){
        System.out.println("Calling B.foo()");
    }

}
public class Clazz implements A, B {
}

Does this code compile?

java: class Clazz inherits unrelated defaults for foo() from
types A and B

Of course not!

How do we fix it?

Option A:

public class Clazz implements A, B {
    public void foo(){}
}

We resolve it manually by overriding the conflicting method.

Option B:

public class Clazz implements A, B {
    public void foo(){
        A.super.foo(); // or B.super.foo()
    }
}

We call the default implementation of method foo() from either interface A or B instead of implementing our own.

Going back to the example of forEach method, how can we force it's default implementation all the iterable collections?

Let's take a look at the Java UML for all the iterable Collections:

In order to add a default behaviour to all the iterable collections, a default forEach method was added to the Iterable<E> interface.

We can find its default implementation in java.lang.iterable interface:

@FunctionalInterface
public interface Iterable {
    Iterator iterator();
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
}

The forEach method takes java.util.function.Consumer functional interface type as a parameter which enables us to pass in a lambda or a method reference as follows:

List<?> list = ...
list.forEach(System.out::println);

However, this is also valid for object of class Set<E> or Queue<E> for example, since both classes implement the Iterable interface.

Summary

Default methods can be seen as a bridge between lambdas and JDK libraries. However, the scope of this feature surpasses the retrocompatibility domain: they can also help reduce the amount of redudant code when dealing with libraries like Swing.

Accumulators

Scalable updatable variables

Accumulators

The continual evolution of uses of concurrency and parallelism in applications requires continual evolution in library support. For this purpose, the Accumulators were introduced.

Accumulators

Maintaining a single count, sum, etc., that is updated by possibly many threads is a common scalability problem.

A set of new classes were created for that purpose:

  • DoubleAccumulator
  • DoubleAdder
  • LongAccumulator
  • LongAdder

Accumulators

Package java.util.concurrent mechanisms synchronized operations between threads, however if all you want to do is increment a variable across threads, it was overkill and then some.

These classes are usually preferable to alternatives when multiple threads update a common value that is used for purposes such as summary statistics that are frequently updated but less frequently read.

Accumulators

Both the DoubleAdder and LongAdder classes can be seen as specific subsets of the DoubleAccumulator and LongAccumulator functionality.

The call new DoubleAdder() is equivalent to

new DoubleAccumulator((x, y) -> x + y, 0.0).

The call new LongAdder() is equivalent to

new LongAccumulator((x, y) -> x + y, 0L).

Examples

DoubleAccumulator da = new DoubleAccumulator((x,y) -> x + y, 0.0);
List<Double> doubles = Arrays.asList(1.0, 2.0, 3.0, 4.0, 10.0);
doubles.forEach(da::accumulate);

System.out.println("Result: " + da.doubleValue());

Output:

Result: 24
LongAdder la = new LongAdder();
List<long> longs = Arrays.asList(10, 20, 30, 40, 100);
longs.forEach(la::accumulate);

System.out.println("Result: " + la.longValue());

Output:

Result: 200

java.util.stream

filter/map/reduce for Java

java.util.stream

ArrayList<Student> students = …;
Stream stream = students.stream(); // sequential version

// parallel version
Stream parallelStream = students.parallelStream();
  • traversed once
  • infinite
  • lazy

java.util.stream

Stream sources

collections

LinkedHashSet set;
Stream stream = set.stream();

generators

Random random = new Random();
Stream randomNumbers = Stream.generate(random::nextInt);

from other streams

Stream newStream = Stream.concat(stream, randomNumbers);

java.util.stream

Intermediate operations

  • .filter - excludes all elements that don’t match a Predicate
  • .map - perform transformation of elements using a Function
  • .flatMap - transform each element into zero or more elements by way of another Stream
  • .peek - performs some action on each element
  • .distinct - excludes all duplicate elements (equals())
  • .sorted - orderered elements (Comparator)
  • .limit - maximum number of elements
  • .substream - range (by index) of elements
List persons = ...;
Stream tenPersonsOver18 = persons.stream()
                           .filter(p -> p.getAge() > 18)
                           .limit(10);

java.util.stream

Terminating operations

Obtain a stream from some sources Perform one or more intermidate operations Perform one terminal operation
  • reducers like reduce(), count(), findAny(), findFirst()
  • collectors (collect())
  • forEach
  • iterators
List<Person> persons = ..;
List<Student> students = persons.stream()
                           .filter(p -> p.getAge() > 18)
                           .map(Student::new)
                           .collect(Collectors.toList());

java.util.stream

Parallel & sequential

List<Person> persons = ..;
List<Student> students = persons.stream()
         .parallel()
         .filter(p -> p.getAge() > 18)
         .sequential()
         .map(Student::new)
         .collect(Collectors.toCollection(ArrayList::new));

java.time

Yet Another Java Date/Time API

java.time

Current Time

Clock clockUTC = Clock.systemUTC();
Clock clockDefault = Clock.systemDefaultZone();
- Different Time Zones

java.time

Time Zones

ZoneId zone = ZoneId.systemDefault();
ZoneId zoneBerlin = ZoneId.of("Europe/Berlin");
Clock clock = Clock.system(zoneBerlin);
- Constructing a Clock using a ZoneId

java.time

Human Readable Time

class LocalDate {
    public static LocalDate now() { ... }
    public static LocalDate now(ZoneId zone) { ... }
    public static LocalDate now(Clock clock) { ... }
}
LocalDate date = LocalDate.now();
System.out.printf("%s-%s-%s",
    date.getYear(), date.getMonthValue(), date.getDayOfMonth());
- now() accepts a Clock or a ZoneId

java.time

Doing Calculations

LocalTime lt = LocalTime.now();
lt.plus(5, ChronoUnit.HOURS);

lt.plusHours(5);

Duration dur = Duration.of(5, ChronoUnit.HOURS);
lt.plus(dur);

Documentation & Interesting Links

THE END