Java 8 is one of the largest upgrades to the popular language and framework in over a decade. This talk will detail several new key features of Java 8 that can help make programs easier to read, write, and maintain. Java 8 comes with many features, especially related to collection libraries. We will...
Java 8 is one of the largest upgrades to the popular language and framework in over a decade. This talk will detail several new key features of Java 8 that can help make programs easier to read, write, and maintain. Java 8 comes with many features, especially related to collection libraries. We will cover such new features as Lambda Expressions, the Stream API, enhanced interfaces, and more.
Size: 650.81 KB
Language: en
Added: Mar 26, 2015
Slides: 56 pages
Slide Content
Introduction toIntroduction to
New Features inNew Features in
Java 8Java 8
Raffi Khatchadourian
Department of Computer Systems Technology
New York City College of Technology
City University of New York
Computer Systems Technology Colloquium
March 26, 2015
Based on slides by Duarte Duarte, Eduardo Martins, Miguel Marques and
Ruben Cordeiro and Horstmann, Cay S. (2014-01-10). Java SE8 for the
Really Impatient: A Short Course on the Basics (Java Series). Pearson
Education.
Some HistorySome History
Java was invented in the 90's as an Object-Oriented language.
Largest change was in ~2005 with Java 5.
Generics.
Enhanced for loops.
Annotations.
Type-safe enumerations.
Concurrency enhancements (AtomicInteger).
Java 8 is MassiveJava 8 is Massive
10 years later, Java 8 is packed with new features.
Core changes are to incorporate functional language features.
We can't cover everything today.
Will focus on some of the more distributive features.
Functional LanguagesFunctional Languages
Declarative ("what not how").
The only state is held in parameters.
Traditionally popular in academia and AI.
Well-suited for event-driven/concurrent ("reactive") programs.
Lambda ExpressionsLambda Expressions
A block of code that you can pass around so it can be
executed later, once or multiple times.
Anonymous methods.
Reduce verbosity caused by anonymous classes.
How are they different from Java methods?
LambdasLambdas
(int x, int y) -> x + y
() -> 42
(String s) -> {System.out.println(s);}
LambdasLambdas
ExamplesExamples
BeforeBefore
Button btn = new Button();
final PrintStream pStream = ...;
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
pStream.println("Button Clicked!");
}
});
AfterAfter
Button btn = new Button();
final PrintStream pStream = ...;
btn.setOnAction(e -> pStream.println( "Button Clicked!"));
Functional InterfacesFunctional Interfaces
Single Abstract Method Type
Functional InterfacesFunctional Interfaces
ExampleExample
@FunctionalInterface
public interface Runnable {
public void run();
}
Runnable r = () -> System.out.println( "Hello World!");
java.util.functionjava.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
Method ReferencesMethod References
Treating an existing method as an instance of a
Functional Interface
Method ReferencesMethod References
ExamplesExamples
class Person {
private String name;
private int age;
public int getAge() {return this.age;}
public String getName() {return this.name;}
}
Person[] people = ...;
Comparator<Person> byName = Comparator.comparing(Person::getName);
Arrays.sort(people, byName);
Method ReferencesMethod References
Kinds of method referencesKinds 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)
Default MethodsDefault Methods
Add default behaviours to interfaces
Why default methods?Why default methods?
Java 8 has lambda expressions. We want to start using them:
List<?> list = ...
list.forEach(...); // lambda code goes here
There's a problemThere's a problem
The forEach method isn’t declared by java.util.List nor the
java.util.Collection interface because doing so would break
existing implementations.
Default MethodsDefault Methods
We have lambdas, but we can't force new behaviours into the current
libraries.
Solution: default methods.
Default MethodsDefault Methods
Traditionally, interfaces can't have method definitions (just
declarations).
Default methods supply default implementations of interface
methods.
ExamplesExamples
Example 1Example 1
BasicsBasics
public interface A {
default void foo() {
System.out.println("Calling A.foo()");
}
}
public class Clazz implements A {
}
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?
Of course not (Java is not C++)!
class Clazz inherits defaults for foo() from both types
A and B
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 a 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);
This is also valid for Sets and Queues, for example, since both classes
implement the Iterable interface.
SummarySummary
Default methods can be seen as a bridge between lambdas and JDK
libraries.
Can be used in interfaces to provide default implementations of
otherwise abstract methods.
Clients can optionally implement (override) them.
static methods are now also allowed in interfaces.
Can eliminate the need for utility classes like .Collections
AccumulatorsAccumulators
The continual evolution of uses of concurrency and parallelism in
applications requires continual evolution in library support. For this
purpose, the Accumulators were introduced.
AccumulatorsAccumulators
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
AccumulatorsAccumulators
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.
AccumulatorsAccumulators
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) .
ExamplesExamples
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: 20
java.util.streamjava.util.stream
filter/map/reduce for Java
java.util.streamjava.util.stream
List<Student> students = …;
Stream stream = students.stream(); // sequential version
// parallel version
Stream parallelStream = students.parallelStream();
traversed once
infinite
lazy
java.util.streamjava.util.stream
Stream sourcesStream sources
CollectionsCollections
Set<Student> set = new LinkedHashSet<>();
Stream<Student> stream = set.stream();
GeneratorsGenerators
Random random = new Random();
Stream<Integer> randomNumbers = Stream.generate(random::nextInt);
From other streamsFrom other streams
Stream newStream = Stream.concat(stream, randomNumbers);
java.util.streamjava.util.stream
Intermediate operationsIntermediate 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<Person> persons = ...;
Stream<Person> tenPersonsOver18 = persons.stream()
.filter(p -> p.getAge() > 18)
.limit( 10);
More examples at: .https://github.com/cst2301-pt13/library-solution
java.util.streamjava.util.stream
Terminating operationsTerminating operations
1. Obtain a stream from some sources
2. Perform one or more intermidate operations
3. 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());