Beyond Modularity
David Gómez G.
@dgomezg
CASTELLÓN
JUG
What Java 9 will do for us?
Modularity?@dgomezg
Java 9 will do for us a lot of things
• Collections factory methods
• Interface changes
• Improvements in Optional<T>
• Stream enhancements
• Multi-release JAR files
• Reactive programming (Flow API)
• Stack Walking API
• New Deprecation
• try with resources improved
• REPL shell
• @safeVarArgs on private instance methods
• emoji in source code
• UTF-8 in property files
• G1 as default collector
• String changes (Compact strings, sharing
interned strings between JVMs)
• Unified JVM logging
• Spin-Wait hints
• VarHandles & Method Handles
@dgomezg
So Java 9 is about
modularity…
Jigsaw. Disabling encapsulation constraints.
$java
WARNING: --permit-illegal-access will
be removed in the next major release
@dgomezg
--permit-illegal-access
Jigsaw. Disabling encapsulation constraints.
$java
WARNING: --permit-illegal-access will
be removed in the next major release
@dgomezg
--illegal-access=permit
Collections
Create & init a list before Java 8
List<String> numbers = Arrays.asList("UNO", "DOS", "TRES");
List<Contact> contacts = new ArrayList<>();
contacts.add(new Contact("David", "Madrid", "555-55 55 55", LocalDate.of(1975, Month.MARCH, 26)));
contacts.add(new Contact("Nando", "Malaga", "555-55 55 56", LocalDate.of(1980, Month.APRIL, 30)));
contacts.add(new Contact("Miguel", "Valencia", "555-66 66 63", LocalDate.of(1983, Month.JUNE, 29)));
contacts.add(new Contact("Ricardo", "Castellón", "555-66 66 64", LocalDate.of(1978, Month.JULY, 4)));
contacts.add(new Contact("Antón", "Vigo", "555-66 66 73", LocalDate.of(1979, Month.SEPTEMBER, 7)));
contacts.add(new Contact("Olivier", "Paris", "555-66 66 61", LocalDate.of(1977, Month.DECEMBER, 22)));
@dgomezg
*
Create & init a Map/Set/… before Java 8
Map<String, Contact> users = new HashMap<>();
users.put("dgomezg", new Contact("David", "Madrid", "555-55 55 55", LocalDate.of(1975, Month.MARCH, 26)));
users.put("rafavindel", new Contact("Rafa", "Madrid", "555-11 11 11", LocalDate.of(1980, Month.FEBRUARY, 10)));
users.put("jlrv", new Contact("Jose Luis", "Madrid", "555-11 11 11", LocalDate.of(1980, Month.APRIL, 10)));
@dgomezg
*
Create & init a Map/Set/… before Java 8
private final Map<String, Contact> speakers = new HashMap<>() {{
put("dgomezg", new Contact("David", "Madrid", "555-55 55 55", LocalDate.of(1975, Month.MARCH, 26)));
put("rafavindel", new Contact("Rafa", "Madrid", "555-11 11 11", LocalDate.of(1980, Month.FEBRUARY, 10)));
put("jlrv", new Contact("Jose Luis", "Madrid", "555-11 11 11", LocalDate.of(1980, Month.APRIL, 10)));
}}
doble bracket syntax
@dgomezg
*
Create & init a Map/Set/… before Java 8
private final Map<String, Contact> speakers = new HashMap<>() {{
put("dgomezg", new Contact("David", "Madrid", "555-55 55 55", LocalDate.of(1975, Month.MARCH, 26)));
put("rafavindel", new Contact("Rafa", "Madrid", "555-11 11 11", LocalDate.of(1980, Month.FEBRUARY, 10)));
put("jlrv", new Contact("Jose Luis", "Madrid", "555-11 11 11", LocalDate.of(1980, Month.APRIL, 10)));
}}
doble bracket syntax
public final List<String> evenNumbers = new ArrayList<>() {{
add("DOS"); add("CUATRO"); add("SEIS");
}};
@dgomezg
*
Create & init a Map/Set/… before Java 8
private final Map<String, Contact> speakers = new HashMap<>() {{
put("dgomezg", new Contact("David", "Madrid", "555-55 55 55", LocalDate.of(1975, Month.MARCH, 26)));
put("rafavindel", new Contact("Rafa", "Madrid", "555-11 11 11", LocalDate.of(1980, Month.FEBRUARY, 10)));
put("jlrv", new Contact("Jose Luis", "Madrid", "555-11 11 11", LocalDate.of(1980, Month.APRIL, 10)));
}}
doble bracket syntax
public final List<String> evenNumbers = new ArrayList<>() {{
add("DOS"); add("CUATRO"); add("SEIS");
}};
public final List<Integer> oddNumbers = new ArrayList<>() {{
for (int i = 1; i < 100; i= i+2) add(i);
}};
@dgomezg
*
Create & init a Collection… Java 8
public final List<Integer> oddNumbers =
Stream.of("UNO", "TRES", "CINCO")
.collect(Collectors.toList());
Streams & generators
@dgomezg
8
Create & init a Collection… Java 8
public final List<Integer> oddNumbers =
Stream.of("UNO", "TRES", "CINCO")
.collect(Collectors.toList());
Streams & generators
public final List<Contact> users =
Files.lines(usersFile)
.map(contact -> ContactParser.parse(contact))
.collect(Collectors.toList());
@dgomezg
8
Create & init a Collection… Java 8
public final List<Integer> oddNumbers =
Stream.of("UNO", "TRES", "CINCO")
.collect(Collectors.toList());
Streams & generators
public static List<Integer> divisibleBy3 =
Stream.iterate(3, t -> t+3).limit(10)
.collect(Collectors.toList());
public final List<Contact> users =
Files.lines(usersFile)
.map(contact -> ContactParser.parse(contact))
.collect(Collectors.toList());
@dgomezg
8
Java 9 Factory Methods. Collections
public final List<String> divisibleBy4 =
List.of("CUATRO", "OCHO", "DOCE", "DIECISEIS");
@dgomezg
9
Java 9 Factory Methods. Collections
public final List<String> divisibleBy4 =
List.of("CUATRO", "OCHO", "DOCE", "DIECISEIS");
public final Set<Integer> negative = Set.of(-1,-2,-3);
@dgomezg
9
Java 9 Factory Methods. Collections
public final List<String> divisibleBy4 =
List.of("CUATRO", "OCHO", "DOCE", "DIECISEIS");
public final Map<String, Integer> numbers = Map.of(
"UNO", 1,
"DOS", 2,
"TRES", 3);
public final Set<Integer> negative = Set.of(-1,-2,-3);
@dgomezg
9
Java 9 Collection Factory Methods. Features
static <E> Set<E> of() {}
static <E> Set<E> of(E e1) {}
static <E> Set<E> of(E e1, E e2) {}
static <E> Set<E> of(E e1, E e2, E e3) {}
[…]
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5,
E e6, E e7, E e8, E e9, E e10) { }
static <E> Set<E> of(E... elements) {}
Overloaded methods for 0..9 parameters & varargs
@dgomezg
9
Java 9 Collection Factory Methods. Features
static <E> Set<E> of(E e1, E e2, E e3) {
return new ImmutableCollections.SetN<>(e1, e2, e3);
}
Return inmutable collections
@dgomezg
9
Java 9 Collection Factory Methods. Features
static <E> Set<E> of() {
return ImmutableCollections.Set0.instance();
}
Empty collections are singleton (reused)
@dgomezg
9
Java 9 Collection Factory Methods. Features
static <E> Set<E> of() {
return ImmutableCollections.Set0.instance();
}
static <E> Set<E> of(E e1) {
return new ImmutableCollections.Set1<>(e1);
}
static <E> Set<E> of(E e1, E e2) {
return new ImmutableCollections.Set2<>(e1, e2);
}
static <E> Set<E> of(E e1, E e2, E e3) {
return new ImmutableCollections.SetN<>(e1, e2, e3);
}
Specific (optimized) implementations for 0,1,2 & N values
@dgomezg
9
Java 9 Collection Factory Methods. Features
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2) {
return new ImmutableCollections.MapN<>(k1, v1, k2, v2);
}
Hidden Entry details on Maps
Map<String, Integer> numbers = Map.of("UNO", 1,"DOS", 2);
Only for length < 10
static <K, V> Map<K, V> ofEntries(Entry<K,V>... entries) { }
@dgomezg
9
Interfaces
(Milling Coin Project)
Interfaces.Once upon a time…
Back in those days when an interface was a contract
@dgomezg
*
Interfaces.Unflexiblity
When you signed a contract, you’re tied forever…
/**

* Implementing this interface allows an object to be the target of

* the "for-each loop" statement. See

* <strong>

* <a href="{@docRoot}/../technotes/guides/language/foreach.html">For-each Loop</a>

* </strong>

*

* @param <T> the type of elements returned by the iterator

*

* @since 1.5

* @jls 14.14.2 The enhanced for statement

*/

public interface Iterable<T> {

/**

* Returns an iterator over elements of type {@code T}.

*

* @return an Iterator.

*/

Iterator<T> iterator();

}
@dgomezg
*
Interfaces.Extension?
Idea: why can’t we add foreach capabilities to Iterators?
Oh WAIT!
/**

* Implementing this interface allows an object to be the target of

* the "for-each loop" statement. See

* <strong>

* <a href="{@docRoot}/../technotes/guides/language/foreach.html">For-each Loop</a>

* </strong>

*

* @param <T> the type of elements returned by the iterator

*

* @since 1.5

* @jls 14.14.2 The enhanced for statement

*/

public interface Iterable<T> {

   /**

    * Returns an iterator over elements of type {@code T}.

    *

    * @return an Iterator.

    */

   Iterator<T> iterator();



   void forEach(Consumer<? super T> action);
}
@dgomezg
*
Interfaces.Java 8 Default methods
Extend contracts (without breaking existing Impls)
aka Defender methods
Convert Complex interfaces in @FunctionalInterfaces
public interface Iterable<T> {



Iterator<T> iterator();



default void forEach(Consumer<? super T> action) {

Objects.requireNonNull(action);

for (T t : this) {

action.accept(t);

}

}
default Spliterator<T> spliterator() {

return Spliterators.spliteratorUnknownSize(iterator(), 0);

}
}
@dgomezg
8
Java 9 Interfaces. Private methods
Keep your code clean:
private methods in interfaces
public interface Iterable<T> {



Iterator<T> iterator();



private void forEach(Consumer<? super T> action) {

Objects.requireNonNull(action);

for (T t : this) {

action.accept(t);

}

}
default Spliterator<T> spliterator() {

return Spliterators.spliteratorUnknownSize(iterator(), 0);

}
}
@dgomezg
9
Java 9 Interfaces. Private methods
public interface Locatable {
GeoPoint getLocation();
default boolean isInside(GeoPoint... points) {
//compose a polygon from points[]
return;
}
default boolean isInBorder(int borderSize, GeoPoint... points) {
//compose a poligon from points[]
//check if distance from getLocation to any edge is less than borderSize
return;
}
}
@dgomezg
9
Java 9 Interfaces. Private methods
public interface Locatable {
GeoPoint getLocation();
default boolean isInside(GeoPoint... points) {
//compose a polygon from points[]
return;
}
default boolean isInBorder(int borderSize, GeoPoint... points) {
//compose a poligon from points[]
//check if distance from getLocation to any edge is less than borderSize
return;
}
private Poligon getPoligonFrom(GeoPoint... points) {
return new Poligon();
}
}
@dgomezg
9
Java 9 Interfaces. Private methods
public interface Locatable {
GeoPoint getLocation();
default boolean isInside(GeoPoint... points) {
//compose a polygon from points[]
getPoligonFrom(points);
return;
}
default boolean isInBorder(int borderSize, GeoPoint... points) {
//compose a poligon from points[]
getPoligonFrom(points);
//check if distance from getLocation to any edge is less than borderSize
return;
}
private Poligon getPoligonFrom(GeoPoint... points) {
return new Poligon();
}
}
@dgomezg
9
Java 8 Interfaces. Static methods
public interface Locatable {
GeoPoint getLocation();
default boolean isInside(GeoPoint... points) {
//compose a polygon from points[]
Locatable.getPoligonFrom(points);
return;
}
default boolean isInBorder(int borderSize, GeoPoint... points) {
//compose a poligon from points[]
Locatable.getPoligonFrom(points);
//check if distance from getLocation to any edge is less than borderSize
return;
}
static Poligon getPoligonFrom(GeoPoint... points) {
return new Poligon();
}
}
@dgomezg
8
Java 9 Interfaces. Private & static access
public class ExclusionArea implements Resizable, Locatable {
public ExclusionArea(GeoPoint... points) {
this.points = Arrays.asList(points);
Locatable.getPoligonFrom(points);
}
}
private methods not accesible
static methods accessible through interface name
@dgomezg
9
Java 9 Interfaces. Private methods. Benefits
Reuse code on your interface extensions
Keep the code clean
Expose only intended methods on API
@dgomezg
Java 9 Interfaces. Don’t be evil
Interfaces are still contracts
Don’t use interfaces to implement multiple inheritance
Diamond problem
Accesibility issues
this and super have different meanings
@dgomezg
Optional
improvements
Optional. More success than expected
Expected only as Return value from methods
“The JSR-335 EG felt fairly strongly that Optional should not
be on any more than needed to support the optional-return
idiom only.
Someone suggested maybe even renaming it to OptionalReturn”
@dgomezg
Optional. More success than expected
Suitable only for certain use cases
Not as field container
Not as method argument
Not to avoid NPE
@dgomezg
Optional. Use cases
public class Contact implements Comparable<Contact> {
private String name;
private String city;
private String phoneNumber;
private final LocalDate birth;
private boolean emergency = false;
} public class ContactBook extends ArrayList<Contact> {
public Optional<Contact> getEmergency() {
return this.getFirstThat(contact -> contact.isEmergency());
}
public Optional<Contact> getFirstContactFromCity(String city) {
return getFirstThat(c -> c.getCity().equalsIgnoreCase(city));
}
private Optional<Contact> getFirstThat(Predicate<Contact> predicate) {
return this.stream().filter(predicate).findFirst();
}
}@dgomezg 8
Optional. Use cases
public class Contact implements Comparable<Contact> {
private String name;
private String city;
private String phoneNumber;
private final LocalDate birth;
private boolean emergency = false;
} public class ContactBook extends ArrayList<Contact> {
public Optional<Contact> getEmergency() {
return this.getFirstThat(Contact::isEmergency);
}
public Optional<Contact> getFirstContactFromCity(String city) {
return getFirstThat(c -> c.getCity().equalsIgnoreCase(city));
}
private Optional<Contact> getFirstThat(Predicate<Contact> predicate) {
return this.stream().filter(predicate).findFirst();
}
}@dgomezg 8
Optional. Initial design problems
the get() design problem
Optional<Contact> emergencyCall = contactBook.getEmergency();
emergencyCall.get().getPhoneNumber();
@dgomezg 8
Optional. Initial design problems
the get() design problem
get throws NoSuchElementException if value not present
We are changing NPE for NoSuchElementException !
Optional<Contact> emergencyCall = contactBook.getEmergency();
emergencyCall.get().getPhoneNumber();
@dgomezg 8
Optional. Initial design problems
the get design problem
method isPresent to avoid Exceptions
Optional<Contact> emergencyCall = contactBook.getEmergency();
if (emergencyCall.isPresent()) {
emergencyCall.get().getPhoneNumber();
}
@dgomezg 8
Optional. Initial design problems
the get design problem
method isPresent to avoid Exceptions
Optional<Contact> emergencyCall = contactBook.getEmergency();
if (emergencyCall.isPresent()) {
emergencyCall.get().getPhoneNumber();
}
Isn’t that a null check?
@dgomezg 8
Optional. Initial design problems
the get design problem
method isPresent to avoid Exceptions
Optional<Contact> emergencyCall = contactBook.getEmergency();
if (emergencyCall.isPresent()) {
emergencyCall.get().getPhoneNumber();
}
Isn’t that a null check?
Contact emergencyCall = contactBook.getEmergency();
if (emergencyCall != null) {
emergencyCall.getPhoneNumber();
}
@dgomezg 8
Optional. Initial design problems
Avoid isPresent & get —> use ifPresent
Optional<Contact> emergencyCall = contactBook.getEmergency();
emergencyCall.ifPresent(contact -> new PhoneDialer().dial(contact));
@dgomezg 8
Optional. Initial design problems
Avoid isPresent & get —> use ifPresent
contactBook.getEmergency()
.ifPresent(contact -> new PhoneDialer().dial(contact));
@dgomezg 8
Optional. Initial design problems
Avoid isPresent & get —> use ifPresent
PhoneDialer phoneDialer = new PhoneDialer();
contactBook.getEmergency()
.ifPresent(contact -> phoneDialer.dial(contact));
@dgomezg 8
Optional. Initial design problems
Avoid isPresent & get —> use ifPresent
PhoneDialer phoneDialer = new PhoneDialer();
contactBook.getEmergency().ifPresent(phoneDialer::dial);
@dgomezg 8
Optional. Initial design problems
Avoid isPresent & get —> use ifPresent
some methods do not consider the alternative case
PhoneDialer phoneDialer = new PhoneDialer();
contactBook.getEmergency().ifPresent(phoneDialer::dial);
@dgomezg 8
Optional. Java 9 improvements
ifPresentOrElse
emergencyCall.ifPresentOrElse(
contact -> phoneDialer.dial(contact),
() -> phoneDialer.dial("112"));
@dgomezg
9
Optional. Java 9 improvements
ifPresentOrElse
requires a Consumer<T> and a Runnable
emergencyCall.ifPresentOrElse(
contact -> phoneDialer.dial(contact),
() -> phoneDialer.dial("112"));
@dgomezg
9
Optional. Java 9 improvements
ifPresentOrElse
requires a Consumer<T> and a Runnable
emergencyCall.ifPresentOrElse(
phoneDialer::dial,
() -> phoneDialer.dial("112"));
@dgomezg
9
Optional. orElseGet
Unify the dialing, by getting a default emergency contact
Contact emergencies = new Contact("Emergencies", "Spain", "112");
String emergencyNumber =
emergencyCall.orElseGet(() -> emergencies)
.getPhoneNumber();
phoneDialer.dial(emergencyNumber);
@dgomezg 8
Optional. orElseGet
Unify the dialing, by getting a default emergency contact
Requires a Supplier<T>
Contact emergencies = new Contact("Emergencies", "Spain", "112");
String emergencyNumber =
emergencyCall.orElseGet(() -> emergencies)
.getPhoneNumber();
phoneDialer.dial(emergencyNumber);
@dgomezg 8
Optional. orElseGet
Unify the dialing, by getting a default emergency contact
Requires a Supplier<T>
Contact emergencies = new Contact("Emergencies", "Spain", "112");
String emergencyNumber =
emergencyCall.orElseGet(() -> emergencies)
.getPhoneNumber();
phoneDialer.dial(emergencyNumber);
@dgomezg 8
orElseGet does not read very well
Optional. Java 9 better or()
or allows to create the Optional with the default value
Contact emergencies = new Contact("Emergencies", "Spain", "112");
Optional<Contact> emergencyCall =
contactBook.getEmergency()
.or(()->Optional.of(emergencies));
String emergencyNumber = emergencyCall.get().getPhoneNumber();
phoneDialer.dial(emergencyNumber);
@dgomezg 9
Optional. Java 9 better or()
or allows to create the Optional with the default value
provide a Supplier<Optional<T>>
Contact emergencies = new Contact("Emergencies", "Spain", "112");
Optional<Contact> emergencyCall =
contactBook.getEmergency()
.or(()->Optional.of(emergencies));
String emergencyNumber = emergencyCall.get().getPhoneNumber();
phoneDialer.dial(emergencyNumber);
@dgomezg 9
Optional. Java 9 better or()
or allows to create the Optional with the default value
provide a Supplier<Optional<T>>
Contact emergencies = new Contact("Emergencies", "Spain", "112");
phoneDialer.dial(contactBook.getEmergency()
.or(()->Optional.of(emergencies))
.get());
@dgomezg
9
Optional. Stream<Optional<T>> (Java 8)
Call a contact for every city in around 40 km.
cities.stream()
.map(contactBook::getFirstContactFromCity)
//now we have Stream<Optional<Contact>>
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(phoneDialer::dial);
@dgomezg 8
Optional. Stream<Optional<T>> (Java 8)
Call a contact for every city in around 40 km.
specific handling of isPresent & get on stream
cities.stream()
.map(contactBook::getFirstContactFromCity)
//now we have Stream<Optional<Contact>>
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(phoneDialer::dial);
@dgomezg 8
Optional. Java 9 Optional.stream()
Call a contact for every city in around 40 km.
cities.stream()
.map(contactBook::getFirstContactFromCity)
.flatMap(Optional::stream)
.forEach(phoneDialer::dial);
@dgomezg 9
Optional. Java 9 Optional.stream()
Call a contact for every city in around 40 km.
Optional.stream() returns a stream of 0 or 1 elements
cities.stream()
.map(contactBook::getFirstContactFromCity)
.flatMap(Optional::stream)
.forEach(phoneDialer::dial);
@dgomezg 9
Stream enhancements
Stream. takeWhile()
Call my friends until 21:30
//call my friends until 21:30
contactBook.stream()
.takeWhile(contact -> LocalTime.now().isBefore(LocalTime.of(21,30)))
.forEach(phoneDialer::dial);
@dgomezg 9
Stream. takeWhile()
Call my friends until 21:30
Depends on stream order (if predicate checks stream items)
//call my friends until 21:30
contactBook.stream()
.takeWhile(contact -> LocalTime.now().isBefore(LocalTime.of(21,30)))
.forEach(phoneDialer::dial);
@dgomezg 9
Stream. takeWhile()
Call my friends until 21:30
Depends on stream order (if predicate checks stream items)
//call my friends until 21:30
contactBook.stream()
.takeWhile(contact -> LocalTime.now().isBefore(LocalTime.of(21,30)))
.forEach(phoneDialer::dial);
Useful to check external conditions to stream
@dgomezg 9
Stream. takeWhile()
Call my friends until 21:30
Depends on stream order (if predicate checks stream items)
//call my friends until 21:30
contactBook.stream()
.takeWhile(__ -> LocalTime.now().isBefore(LocalTime.of(21,30)))
.forEach(phoneDialer::dial);
Useful to check external conditions to stream
@dgomezg 9
Stream. takeWhile()
Files.lines(Paths.get("urls.txt"))
.takeWhile(__ -> running)
.forEach(url -> URLChecker::checkAlive);
Useful to check external conditions to stream
@dgomezg 9
Stream. takeWhile()
Files.lines(Paths.get("urls.txt"))
.takeWhile(__ -> running)
.forEach(url -> URLChecker::checkAlive);
Useful to check external conditions to stream
Allows us to stop infinite streams
@dgomezg 9
Stream. dropWhile()
Files.lines(Paths.get("urls.txt"))
.dropWhile(__ -> !running)
.forEach(url -> URLChecker::checkAlive);
Ignore events until a certain condition
@dgomezg 9
Stream. dropWhile()
Files.lines(Paths.get("urls.txt"))
.dropWhile(__ -> !running)
.forEach(url -> URLChecker::checkAlive);
Ignore events until a certain condition
Also depends on stream order
(if checking stream elements)
@dgomezg 9
Stream. new iterate method
IntStream infiniteEvenNumbers = IntStream.iterate(0, i -> i+2);
Iterate returns infinite streams
@dgomezg 89
8
Stream. new iterate method
IntStream infiniteEvenNumbers = IntStream.iterate(0, i -> i+2);
Iterate returns infinite streams
Beware of stateful operations: sort(), max(), …
@dgomezg 89
8
Stream. new iterate method
IntStream infiniteEvenNumbers = IntStream.iterate(0, i -> i+2);
Iterate returns infinite streams
Beware of stateful operations: sort(), max(), …
IntStream evenNumbers = IntStream.iterate(0, i -> i < 500, i -> i+2);
IntStream evenNumbers = IntStream.iterate(0, __ -> running, i -> i+2);
Better use iterate with hasNext() predicate
@dgomezg 89
8
Stream. ofNullable
/**
* Returns a sequential {@code Stream} containing a single element, if
* non-null, otherwise returns an empty {@code Stream}.
*
* @param t the single element
* @param <T> the type of stream elements
* @return a stream with a single element if the specified element
* is non-null, otherwise an empty stream
* @since 9
*/
public static<T> Stream<T> ofNullable(T t) {
return t == null ? Stream.empty()
: StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
}
Static method to create an empty Stream in case of null
@dgomezg
9
Stream. Files::lines in parallel
Files.lines(Paths.get(“urls.txt"))
.parallel()
.dropWhile(__ -> !running)
.forEach(URLChecker::checkAlive);
File::lines was sequential
@dgomezg 9
Stream. Files::lines in parallel
Files.lines(Paths.get(“urls.txt"))
.parallel()
.dropWhile(__ -> !running)
.forEach(URLChecker::checkAlive);
File::lines was sequential
Now it uses Memory mapped files to allow parallelization
@dgomezg 9
Multi-release Jar Files
Multirelease JAR files
Distributions that adapt to running environment
Useful for libraries and frameworks
JAR content root
A.class
B.class
C.class
D.class
META-INF
MANIFEST.MF
versions
9
A.class
B.class
10
A.class
@dgomezg 9
Flow API
Components
@dgomezg 9
Components
@dgomezg 9
Components
@dgomezg 9
Components
@dgomezg 9
Components
@dgomezg 9
Components
@dgomezg 9
Components
@dgomezg 9
Components
@dgomezg 9
Components
@dgomezg 9
Implementations
Project Reactor
Reactive Streams
Spring 5
@dgomezg
Stack Walking
Throwable vs StackWalker. Performance
StackTraceElement[] stackTrace = new Throwable().getStackTrace();
StackWalker stackWalker = StackWalker.getInstance();
@dgomezg 9
Benefits
ThreadSafe
Simple access (StackWalker.getInstance())
Returns a stream
Filter, assert & skip specific classes
Instance of declaring class
Limiting depth
@dgomezg
Instantiation
StackWalker.getInstance()
StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
StackWalker.getInstance(Set.of(
StackWalker.Option.RETAIN_CLASS_REFERENCE,
StackWalker.Option.SHOW_HIDDEN_FRAMES,
StackWalker.Option.SHOW_REFLECT_FRAMES));
StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE, estimatedDepth);
@dgomezg 9
Operations
.forEach(System.out::println);
.getCallerClass();
.walk(FunctionFunction<? super Stream<StackFrame>, ? extends T> function);
StackWalker.getInstance()
//returns stack depth
StackWalker.getInstance().walk(stackStream -> stackStream.count());
//filter only lambdas
StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
.walk(s -> s.map(StackWalker.StackFrame::getMethodName)
.limit(10)
.filter(methodName -> methodName.contains("lambda"))
.count())
@dgomezg 9
LoggerFactory
public class MyLoggerFactory {
public static Logger getLogger() {
Class<?> clazz = StackWalker
.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
.getCallerClass();
return LoggerFactory.getLogger(clazz);
}
}
public class StackWalkerExample {
private static Logger LOGGER = MyLoggerFactory.getLogger();
}
@dgomezg 9
Throwable vs StackWalker. performance
Microbenchmark by Pierre Laporte
https://github.com/pingtimeout/stack-walker-benchmark
$ java -jar target/microbenchmarks.jar -f 5 -wi 10 -i 10
[...]
# Run complete. Total time: 00:14:52
Benchmark Mode Cnt Score Error Units
FileAndLineNumberBenchmark.exception avgt 50 22414.893 ± 456.006 ns/op
FileAndLineNumberBenchmark.stackwalkerWithClassAndBCI avgt 50 3699.118 ± 53.813 ns/op
FileAndLineNumberBenchmark.stackwalkerWithClassMethodAndBCI avgt 50 6618.887 ± 129.552 ns/op
FileAndLineNumberBenchmark.stackwalkerWithExplicitStackTraceElement avgt 50 9043.039 ± 167.530 ns/op
FileAndLineNumberBenchmark.stackwalkerWithFileNameAndLineNumber avgt 50 12286.137 ± 377.900 ns/op
StackTraceBenchmark.exception avgt 50 21224.342 ± 453.239 ns/op
StackTraceBenchmark.stackwalker avgt 50 3573.991 ± 71.692 ns/op
@dgomezg 9
New Deprecation
Attributes added to @Deprecated
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
public @interface Deprecated {
/**
* Returns the version in which the annotated element became deprecated.
* The version string is in the same format and namespace as the value of
* the {@code @since} javadoc tag. The default value is the empty string.
*
* @return the version string
* @since 9
*/
String since() default "";
/**
* Indicates whether the annotated element is subject to removal in a
* future version. The default value is {@code false}.
*
* @return whether the element is subject to removal
* @since 9
*/
boolean forRemoval() default false;
}
public class Contact implements Comparable<Contact> {
@Deprecated(since=“1.1.3”, forRemoval = true)
public Period getAge() {
return Period.between(getBirth(), LocalDate.now());
}
}@dgomezg
9
Try with Resources
Before java 7
public class FileReadingJava6 {
public static void main(String[] args) throws Exception {
BufferedReader br = null;
try {
String line;
br = new BufferedReader(new FileReader(getFile("log4j.xml")));
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null)br.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
@dgomezg
< 7
Java 7
public class FileReadingJava7 {
public static void main(String[] args) {
try (BufferedReader br =
new BufferedReader(new FileReader(getFile("log4j.xml")));){
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
} //br is closed automatically
}
}
@dgomezg 7
Java 7. With a provided resource
public class FileReaderJava7WithProvidedReader {
public void printContents(BufferedReader reader) {
try (BufferedReader br = reader){
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
} //br is closed automatically and so, also the reader.
}
public static void main(String[] args) throws Exception {
BufferedReader br =
new BufferedReader(new FileReader(getFile("log4j.xml")));
new FileReaderJava7WithProvidedReader().printContents(br);
}
} 7
Java 9
public class FileReaderJava9 {
public void printContents(BufferedReader reader) {
try (reader) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
} //reader is closed automatically
}
public static void main(String[] args) throws Exception {
BufferedReader br =
new BufferedReader(new FileReader(getFile("log4j.xml")));
new FileReaderJava9().printContents(br);
}
}
@dgomezg
9
VarHandles
The Unsafe apocalypse
@dgomezg
The Unsafe apocalypse
sun.misc.Unsafe
@dgomezg
The Unsafe apocalypse
sun.misc.Unsafe
create objects without invoking constructors
access to direct native memory
Intended to be used only by JVM
@dgomezg
The Unsafe apocalypse
sun.misc.Unsafe
create objects without invoking constructors
access to direct native memory
Intended to be used only by JVM
but everyone is using it to do ‘cool’ things
@dgomezg
The Unsafe apocalypse
sun.misc.Unsafe
create objects without invoking constructors
access to direct native memory
Intended to be used only by JVM
but everyone is using it to do ‘cool’ things
Not removed but will be gradually offering alternatives
@dgomezg
VarHandles as alternative
class Foo {
int i;
}
Typed reference to variable
Abstraction to safe access to a memory location
class Bar {
static final VarHandle VH_FOO_FIELD_I;
static {
try {
VH_FOO_FIELD_I = MethodHandles.lookup().
in(Foo.class).
findVarHandle(Foo.class, "i", int.class);
} catch (Exception e) {
throw new Error(e);
}
}
}
@dgomezg 9
VarHandles as alternative
Fenced operations
CompareAndSwap operations
Volatile operations
@dgomezg 9
String changes
Strings everywhere.
String optimization to concatenate
String.intern()
At first only done by compiler (or manually)
Then by GC with -XX:+UseStringDeduplication (moved from
PermGen to Heap in Java8)
String compactation
XX:+UsedCompressedStrings optional in Java 6 (uses char[])
XX:+CompactStrings by default on java 9 (uses byte[])
@dgomezg
Other minor changes
The list goes on…
• @SafeVarArgs on private instance methods
• emoji in source code
• UTF-8 in property files
• _ not allowed as identifier
• Unified JVM logging
• Spin-Wait hints
@dgomezg
The list goes on…
• @SafeVarArgs on private instance methods
• emoji in source code
• UTF-8 in property files
• _ not allowed as identifier
• Unified JVM logging
• Spin-Wait hints
// This comment is 💩
@dgomezg
… and on …
@dgomezg
Conclusions
The bright side. Java 9 is more than just Jigsaw
• Complements the APIs and from Java8
• Streams
• Optionals
• Adds new APIs
• Reactive streams and Flow API
• Improved support for Concurrency and Asyncronous
Futures
• StackWalker
• Improves performance
• String computation
• G1GC
@dgomezg
Thank You.
@dgomezg
dgomezg@autentia.com
CASTELLÓN
JUG

Java9 Beyond Modularity - Java 9 más allá de la modularidad

  • 1.
    Beyond Modularity David GómezG. @dgomezg CASTELLÓN JUG
  • 2.
    What Java 9will do for us? Modularity?@dgomezg
  • 3.
    Java 9 willdo for us a lot of things • Collections factory methods • Interface changes • Improvements in Optional<T> • Stream enhancements • Multi-release JAR files • Reactive programming (Flow API) • Stack Walking API • New Deprecation • try with resources improved • REPL shell • @safeVarArgs on private instance methods • emoji in source code • UTF-8 in property files • G1 as default collector • String changes (Compact strings, sharing interned strings between JVMs) • Unified JVM logging • Spin-Wait hints • VarHandles & Method Handles @dgomezg
  • 4.
    So Java 9is about modularity…
  • 5.
    Jigsaw. Disabling encapsulationconstraints. $java WARNING: --permit-illegal-access will be removed in the next major release @dgomezg --permit-illegal-access
  • 6.
    Jigsaw. Disabling encapsulationconstraints. $java WARNING: --permit-illegal-access will be removed in the next major release @dgomezg --illegal-access=permit
  • 7.
  • 8.
    Create & inita list before Java 8 List<String> numbers = Arrays.asList("UNO", "DOS", "TRES"); List<Contact> contacts = new ArrayList<>(); contacts.add(new Contact("David", "Madrid", "555-55 55 55", LocalDate.of(1975, Month.MARCH, 26))); contacts.add(new Contact("Nando", "Malaga", "555-55 55 56", LocalDate.of(1980, Month.APRIL, 30))); contacts.add(new Contact("Miguel", "Valencia", "555-66 66 63", LocalDate.of(1983, Month.JUNE, 29))); contacts.add(new Contact("Ricardo", "Castellón", "555-66 66 64", LocalDate.of(1978, Month.JULY, 4))); contacts.add(new Contact("Antón", "Vigo", "555-66 66 73", LocalDate.of(1979, Month.SEPTEMBER, 7))); contacts.add(new Contact("Olivier", "Paris", "555-66 66 61", LocalDate.of(1977, Month.DECEMBER, 22))); @dgomezg *
  • 9.
    Create & inita Map/Set/… before Java 8 Map<String, Contact> users = new HashMap<>(); users.put("dgomezg", new Contact("David", "Madrid", "555-55 55 55", LocalDate.of(1975, Month.MARCH, 26))); users.put("rafavindel", new Contact("Rafa", "Madrid", "555-11 11 11", LocalDate.of(1980, Month.FEBRUARY, 10))); users.put("jlrv", new Contact("Jose Luis", "Madrid", "555-11 11 11", LocalDate.of(1980, Month.APRIL, 10))); @dgomezg *
  • 10.
    Create & inita Map/Set/… before Java 8 private final Map<String, Contact> speakers = new HashMap<>() {{ put("dgomezg", new Contact("David", "Madrid", "555-55 55 55", LocalDate.of(1975, Month.MARCH, 26))); put("rafavindel", new Contact("Rafa", "Madrid", "555-11 11 11", LocalDate.of(1980, Month.FEBRUARY, 10))); put("jlrv", new Contact("Jose Luis", "Madrid", "555-11 11 11", LocalDate.of(1980, Month.APRIL, 10))); }} doble bracket syntax @dgomezg *
  • 11.
    Create & inita Map/Set/… before Java 8 private final Map<String, Contact> speakers = new HashMap<>() {{ put("dgomezg", new Contact("David", "Madrid", "555-55 55 55", LocalDate.of(1975, Month.MARCH, 26))); put("rafavindel", new Contact("Rafa", "Madrid", "555-11 11 11", LocalDate.of(1980, Month.FEBRUARY, 10))); put("jlrv", new Contact("Jose Luis", "Madrid", "555-11 11 11", LocalDate.of(1980, Month.APRIL, 10))); }} doble bracket syntax public final List<String> evenNumbers = new ArrayList<>() {{ add("DOS"); add("CUATRO"); add("SEIS"); }}; @dgomezg *
  • 12.
    Create & inita Map/Set/… before Java 8 private final Map<String, Contact> speakers = new HashMap<>() {{ put("dgomezg", new Contact("David", "Madrid", "555-55 55 55", LocalDate.of(1975, Month.MARCH, 26))); put("rafavindel", new Contact("Rafa", "Madrid", "555-11 11 11", LocalDate.of(1980, Month.FEBRUARY, 10))); put("jlrv", new Contact("Jose Luis", "Madrid", "555-11 11 11", LocalDate.of(1980, Month.APRIL, 10))); }} doble bracket syntax public final List<String> evenNumbers = new ArrayList<>() {{ add("DOS"); add("CUATRO"); add("SEIS"); }}; public final List<Integer> oddNumbers = new ArrayList<>() {{ for (int i = 1; i < 100; i= i+2) add(i); }}; @dgomezg *
  • 13.
    Create & inita Collection… Java 8 public final List<Integer> oddNumbers = Stream.of("UNO", "TRES", "CINCO") .collect(Collectors.toList()); Streams & generators @dgomezg 8
  • 14.
    Create & inita Collection… Java 8 public final List<Integer> oddNumbers = Stream.of("UNO", "TRES", "CINCO") .collect(Collectors.toList()); Streams & generators public final List<Contact> users = Files.lines(usersFile) .map(contact -> ContactParser.parse(contact)) .collect(Collectors.toList()); @dgomezg 8
  • 15.
    Create & inita Collection… Java 8 public final List<Integer> oddNumbers = Stream.of("UNO", "TRES", "CINCO") .collect(Collectors.toList()); Streams & generators public static List<Integer> divisibleBy3 = Stream.iterate(3, t -> t+3).limit(10) .collect(Collectors.toList()); public final List<Contact> users = Files.lines(usersFile) .map(contact -> ContactParser.parse(contact)) .collect(Collectors.toList()); @dgomezg 8
  • 16.
    Java 9 FactoryMethods. Collections public final List<String> divisibleBy4 = List.of("CUATRO", "OCHO", "DOCE", "DIECISEIS"); @dgomezg 9
  • 17.
    Java 9 FactoryMethods. Collections public final List<String> divisibleBy4 = List.of("CUATRO", "OCHO", "DOCE", "DIECISEIS"); public final Set<Integer> negative = Set.of(-1,-2,-3); @dgomezg 9
  • 18.
    Java 9 FactoryMethods. Collections public final List<String> divisibleBy4 = List.of("CUATRO", "OCHO", "DOCE", "DIECISEIS"); public final Map<String, Integer> numbers = Map.of( "UNO", 1, "DOS", 2, "TRES", 3); public final Set<Integer> negative = Set.of(-1,-2,-3); @dgomezg 9
  • 19.
    Java 9 CollectionFactory Methods. Features static <E> Set<E> of() {} static <E> Set<E> of(E e1) {} static <E> Set<E> of(E e1, E e2) {} static <E> Set<E> of(E e1, E e2, E e3) {} […] static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) { } static <E> Set<E> of(E... elements) {} Overloaded methods for 0..9 parameters & varargs @dgomezg 9
  • 20.
    Java 9 CollectionFactory Methods. Features static <E> Set<E> of(E e1, E e2, E e3) { return new ImmutableCollections.SetN<>(e1, e2, e3); } Return inmutable collections @dgomezg 9
  • 21.
    Java 9 CollectionFactory Methods. Features static <E> Set<E> of() { return ImmutableCollections.Set0.instance(); } Empty collections are singleton (reused) @dgomezg 9
  • 22.
    Java 9 CollectionFactory Methods. Features static <E> Set<E> of() { return ImmutableCollections.Set0.instance(); } static <E> Set<E> of(E e1) { return new ImmutableCollections.Set1<>(e1); } static <E> Set<E> of(E e1, E e2) { return new ImmutableCollections.Set2<>(e1, e2); } static <E> Set<E> of(E e1, E e2, E e3) { return new ImmutableCollections.SetN<>(e1, e2, e3); } Specific (optimized) implementations for 0,1,2 & N values @dgomezg 9
  • 23.
    Java 9 CollectionFactory Methods. Features static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2) { return new ImmutableCollections.MapN<>(k1, v1, k2, v2); } Hidden Entry details on Maps Map<String, Integer> numbers = Map.of("UNO", 1,"DOS", 2); Only for length < 10 static <K, V> Map<K, V> ofEntries(Entry<K,V>... entries) { } @dgomezg 9
  • 24.
  • 25.
    Interfaces.Once upon atime… Back in those days when an interface was a contract @dgomezg *
  • 26.
    Interfaces.Unflexiblity When you signeda contract, you’re tied forever… /**
 * Implementing this interface allows an object to be the target of
 * the "for-each loop" statement. See
 * <strong>
 * <a href="{@docRoot}/../technotes/guides/language/foreach.html">For-each Loop</a>
 * </strong>
 *
 * @param <T> the type of elements returned by the iterator
 *
 * @since 1.5
 * @jls 14.14.2 The enhanced for statement
 */
 public interface Iterable<T> {
 /**
 * Returns an iterator over elements of type {@code T}.
 *
 * @return an Iterator.
 */
 Iterator<T> iterator();
 } @dgomezg *
  • 27.
    Interfaces.Extension? Idea: why can’twe add foreach capabilities to Iterators? Oh WAIT! /**
 * Implementing this interface allows an object to be the target of
 * the "for-each loop" statement. See
 * <strong>
 * <a href="{@docRoot}/../technotes/guides/language/foreach.html">For-each Loop</a>
 * </strong>
 *
 * @param <T> the type of elements returned by the iterator
 *
 * @since 1.5
 * @jls 14.14.2 The enhanced for statement
 */
 public interface Iterable<T> {
    /**
     * Returns an iterator over elements of type {@code T}.
     *
     * @return an Iterator.
     */
    Iterator<T> iterator();
 
    void forEach(Consumer<? super T> action); } @dgomezg *
  • 28.
    Interfaces.Java 8 Defaultmethods Extend contracts (without breaking existing Impls) aka Defender methods Convert Complex interfaces in @FunctionalInterfaces public interface Iterable<T> {
 
 Iterator<T> iterator();
 
 default void forEach(Consumer<? super T> action) {
 Objects.requireNonNull(action);
 for (T t : this) {
 action.accept(t);
 }
 } default Spliterator<T> spliterator() {
 return Spliterators.spliteratorUnknownSize(iterator(), 0);
 } } @dgomezg 8
  • 29.
    Java 9 Interfaces.Private methods Keep your code clean: private methods in interfaces public interface Iterable<T> {
 
 Iterator<T> iterator();
 
 private void forEach(Consumer<? super T> action) {
 Objects.requireNonNull(action);
 for (T t : this) {
 action.accept(t);
 }
 } default Spliterator<T> spliterator() {
 return Spliterators.spliteratorUnknownSize(iterator(), 0);
 } } @dgomezg 9
  • 30.
    Java 9 Interfaces.Private methods public interface Locatable { GeoPoint getLocation(); default boolean isInside(GeoPoint... points) { //compose a polygon from points[] return; } default boolean isInBorder(int borderSize, GeoPoint... points) { //compose a poligon from points[] //check if distance from getLocation to any edge is less than borderSize return; } } @dgomezg 9
  • 31.
    Java 9 Interfaces.Private methods public interface Locatable { GeoPoint getLocation(); default boolean isInside(GeoPoint... points) { //compose a polygon from points[] return; } default boolean isInBorder(int borderSize, GeoPoint... points) { //compose a poligon from points[] //check if distance from getLocation to any edge is less than borderSize return; } private Poligon getPoligonFrom(GeoPoint... points) { return new Poligon(); } } @dgomezg 9
  • 32.
    Java 9 Interfaces.Private methods public interface Locatable { GeoPoint getLocation(); default boolean isInside(GeoPoint... points) { //compose a polygon from points[] getPoligonFrom(points); return; } default boolean isInBorder(int borderSize, GeoPoint... points) { //compose a poligon from points[] getPoligonFrom(points); //check if distance from getLocation to any edge is less than borderSize return; } private Poligon getPoligonFrom(GeoPoint... points) { return new Poligon(); } } @dgomezg 9
  • 33.
    Java 8 Interfaces.Static methods public interface Locatable { GeoPoint getLocation(); default boolean isInside(GeoPoint... points) { //compose a polygon from points[] Locatable.getPoligonFrom(points); return; } default boolean isInBorder(int borderSize, GeoPoint... points) { //compose a poligon from points[] Locatable.getPoligonFrom(points); //check if distance from getLocation to any edge is less than borderSize return; } static Poligon getPoligonFrom(GeoPoint... points) { return new Poligon(); } } @dgomezg 8
  • 34.
    Java 9 Interfaces.Private & static access public class ExclusionArea implements Resizable, Locatable { public ExclusionArea(GeoPoint... points) { this.points = Arrays.asList(points); Locatable.getPoligonFrom(points); } } private methods not accesible static methods accessible through interface name @dgomezg 9
  • 35.
    Java 9 Interfaces.Private methods. Benefits Reuse code on your interface extensions Keep the code clean Expose only intended methods on API @dgomezg
  • 36.
    Java 9 Interfaces.Don’t be evil Interfaces are still contracts Don’t use interfaces to implement multiple inheritance Diamond problem Accesibility issues this and super have different meanings @dgomezg
  • 37.
  • 38.
    Optional. More successthan expected Expected only as Return value from methods “The JSR-335 EG felt fairly strongly that Optional should not be on any more than needed to support the optional-return idiom only. Someone suggested maybe even renaming it to OptionalReturn” @dgomezg
  • 39.
    Optional. More successthan expected Suitable only for certain use cases Not as field container Not as method argument Not to avoid NPE @dgomezg
  • 40.
    Optional. Use cases publicclass Contact implements Comparable<Contact> { private String name; private String city; private String phoneNumber; private final LocalDate birth; private boolean emergency = false; } public class ContactBook extends ArrayList<Contact> { public Optional<Contact> getEmergency() { return this.getFirstThat(contact -> contact.isEmergency()); } public Optional<Contact> getFirstContactFromCity(String city) { return getFirstThat(c -> c.getCity().equalsIgnoreCase(city)); } private Optional<Contact> getFirstThat(Predicate<Contact> predicate) { return this.stream().filter(predicate).findFirst(); } }@dgomezg 8
  • 41.
    Optional. Use cases publicclass Contact implements Comparable<Contact> { private String name; private String city; private String phoneNumber; private final LocalDate birth; private boolean emergency = false; } public class ContactBook extends ArrayList<Contact> { public Optional<Contact> getEmergency() { return this.getFirstThat(Contact::isEmergency); } public Optional<Contact> getFirstContactFromCity(String city) { return getFirstThat(c -> c.getCity().equalsIgnoreCase(city)); } private Optional<Contact> getFirstThat(Predicate<Contact> predicate) { return this.stream().filter(predicate).findFirst(); } }@dgomezg 8
  • 42.
    Optional. Initial designproblems the get() design problem Optional<Contact> emergencyCall = contactBook.getEmergency(); emergencyCall.get().getPhoneNumber(); @dgomezg 8
  • 43.
    Optional. Initial designproblems the get() design problem get throws NoSuchElementException if value not present We are changing NPE for NoSuchElementException ! Optional<Contact> emergencyCall = contactBook.getEmergency(); emergencyCall.get().getPhoneNumber(); @dgomezg 8
  • 44.
    Optional. Initial designproblems the get design problem method isPresent to avoid Exceptions Optional<Contact> emergencyCall = contactBook.getEmergency(); if (emergencyCall.isPresent()) { emergencyCall.get().getPhoneNumber(); } @dgomezg 8
  • 45.
    Optional. Initial designproblems the get design problem method isPresent to avoid Exceptions Optional<Contact> emergencyCall = contactBook.getEmergency(); if (emergencyCall.isPresent()) { emergencyCall.get().getPhoneNumber(); } Isn’t that a null check? @dgomezg 8
  • 46.
    Optional. Initial designproblems the get design problem method isPresent to avoid Exceptions Optional<Contact> emergencyCall = contactBook.getEmergency(); if (emergencyCall.isPresent()) { emergencyCall.get().getPhoneNumber(); } Isn’t that a null check? Contact emergencyCall = contactBook.getEmergency(); if (emergencyCall != null) { emergencyCall.getPhoneNumber(); } @dgomezg 8
  • 47.
    Optional. Initial designproblems Avoid isPresent & get —> use ifPresent Optional<Contact> emergencyCall = contactBook.getEmergency(); emergencyCall.ifPresent(contact -> new PhoneDialer().dial(contact)); @dgomezg 8
  • 48.
    Optional. Initial designproblems Avoid isPresent & get —> use ifPresent contactBook.getEmergency() .ifPresent(contact -> new PhoneDialer().dial(contact)); @dgomezg 8
  • 49.
    Optional. Initial designproblems Avoid isPresent & get —> use ifPresent PhoneDialer phoneDialer = new PhoneDialer(); contactBook.getEmergency() .ifPresent(contact -> phoneDialer.dial(contact)); @dgomezg 8
  • 50.
    Optional. Initial designproblems Avoid isPresent & get —> use ifPresent PhoneDialer phoneDialer = new PhoneDialer(); contactBook.getEmergency().ifPresent(phoneDialer::dial); @dgomezg 8
  • 51.
    Optional. Initial designproblems Avoid isPresent & get —> use ifPresent some methods do not consider the alternative case PhoneDialer phoneDialer = new PhoneDialer(); contactBook.getEmergency().ifPresent(phoneDialer::dial); @dgomezg 8
  • 52.
    Optional. Java 9improvements ifPresentOrElse emergencyCall.ifPresentOrElse( contact -> phoneDialer.dial(contact), () -> phoneDialer.dial("112")); @dgomezg 9
  • 53.
    Optional. Java 9improvements ifPresentOrElse requires a Consumer<T> and a Runnable emergencyCall.ifPresentOrElse( contact -> phoneDialer.dial(contact), () -> phoneDialer.dial("112")); @dgomezg 9
  • 54.
    Optional. Java 9improvements ifPresentOrElse requires a Consumer<T> and a Runnable emergencyCall.ifPresentOrElse( phoneDialer::dial, () -> phoneDialer.dial("112")); @dgomezg 9
  • 55.
    Optional. orElseGet Unify thedialing, by getting a default emergency contact Contact emergencies = new Contact("Emergencies", "Spain", "112"); String emergencyNumber = emergencyCall.orElseGet(() -> emergencies) .getPhoneNumber(); phoneDialer.dial(emergencyNumber); @dgomezg 8
  • 56.
    Optional. orElseGet Unify thedialing, by getting a default emergency contact Requires a Supplier<T> Contact emergencies = new Contact("Emergencies", "Spain", "112"); String emergencyNumber = emergencyCall.orElseGet(() -> emergencies) .getPhoneNumber(); phoneDialer.dial(emergencyNumber); @dgomezg 8
  • 57.
    Optional. orElseGet Unify thedialing, by getting a default emergency contact Requires a Supplier<T> Contact emergencies = new Contact("Emergencies", "Spain", "112"); String emergencyNumber = emergencyCall.orElseGet(() -> emergencies) .getPhoneNumber(); phoneDialer.dial(emergencyNumber); @dgomezg 8 orElseGet does not read very well
  • 58.
    Optional. Java 9better or() or allows to create the Optional with the default value Contact emergencies = new Contact("Emergencies", "Spain", "112"); Optional<Contact> emergencyCall = contactBook.getEmergency() .or(()->Optional.of(emergencies)); String emergencyNumber = emergencyCall.get().getPhoneNumber(); phoneDialer.dial(emergencyNumber); @dgomezg 9
  • 59.
    Optional. Java 9better or() or allows to create the Optional with the default value provide a Supplier<Optional<T>> Contact emergencies = new Contact("Emergencies", "Spain", "112"); Optional<Contact> emergencyCall = contactBook.getEmergency() .or(()->Optional.of(emergencies)); String emergencyNumber = emergencyCall.get().getPhoneNumber(); phoneDialer.dial(emergencyNumber); @dgomezg 9
  • 60.
    Optional. Java 9better or() or allows to create the Optional with the default value provide a Supplier<Optional<T>> Contact emergencies = new Contact("Emergencies", "Spain", "112"); phoneDialer.dial(contactBook.getEmergency() .or(()->Optional.of(emergencies)) .get()); @dgomezg 9
  • 61.
    Optional. Stream<Optional<T>> (Java8) Call a contact for every city in around 40 km. cities.stream() .map(contactBook::getFirstContactFromCity) //now we have Stream<Optional<Contact>> .filter(Optional::isPresent) .map(Optional::get) .forEach(phoneDialer::dial); @dgomezg 8
  • 62.
    Optional. Stream<Optional<T>> (Java8) Call a contact for every city in around 40 km. specific handling of isPresent & get on stream cities.stream() .map(contactBook::getFirstContactFromCity) //now we have Stream<Optional<Contact>> .filter(Optional::isPresent) .map(Optional::get) .forEach(phoneDialer::dial); @dgomezg 8
  • 63.
    Optional. Java 9Optional.stream() Call a contact for every city in around 40 km. cities.stream() .map(contactBook::getFirstContactFromCity) .flatMap(Optional::stream) .forEach(phoneDialer::dial); @dgomezg 9
  • 64.
    Optional. Java 9Optional.stream() Call a contact for every city in around 40 km. Optional.stream() returns a stream of 0 or 1 elements cities.stream() .map(contactBook::getFirstContactFromCity) .flatMap(Optional::stream) .forEach(phoneDialer::dial); @dgomezg 9
  • 65.
  • 66.
    Stream. takeWhile() Call myfriends until 21:30 //call my friends until 21:30 contactBook.stream() .takeWhile(contact -> LocalTime.now().isBefore(LocalTime.of(21,30))) .forEach(phoneDialer::dial); @dgomezg 9
  • 67.
    Stream. takeWhile() Call myfriends until 21:30 Depends on stream order (if predicate checks stream items) //call my friends until 21:30 contactBook.stream() .takeWhile(contact -> LocalTime.now().isBefore(LocalTime.of(21,30))) .forEach(phoneDialer::dial); @dgomezg 9
  • 68.
    Stream. takeWhile() Call myfriends until 21:30 Depends on stream order (if predicate checks stream items) //call my friends until 21:30 contactBook.stream() .takeWhile(contact -> LocalTime.now().isBefore(LocalTime.of(21,30))) .forEach(phoneDialer::dial); Useful to check external conditions to stream @dgomezg 9
  • 69.
    Stream. takeWhile() Call myfriends until 21:30 Depends on stream order (if predicate checks stream items) //call my friends until 21:30 contactBook.stream() .takeWhile(__ -> LocalTime.now().isBefore(LocalTime.of(21,30))) .forEach(phoneDialer::dial); Useful to check external conditions to stream @dgomezg 9
  • 70.
    Stream. takeWhile() Files.lines(Paths.get("urls.txt")) .takeWhile(__ ->running) .forEach(url -> URLChecker::checkAlive); Useful to check external conditions to stream @dgomezg 9
  • 71.
    Stream. takeWhile() Files.lines(Paths.get("urls.txt")) .takeWhile(__ ->running) .forEach(url -> URLChecker::checkAlive); Useful to check external conditions to stream Allows us to stop infinite streams @dgomezg 9
  • 72.
    Stream. dropWhile() Files.lines(Paths.get("urls.txt")) .dropWhile(__ ->!running) .forEach(url -> URLChecker::checkAlive); Ignore events until a certain condition @dgomezg 9
  • 73.
    Stream. dropWhile() Files.lines(Paths.get("urls.txt")) .dropWhile(__ ->!running) .forEach(url -> URLChecker::checkAlive); Ignore events until a certain condition Also depends on stream order (if checking stream elements) @dgomezg 9
  • 74.
    Stream. new iteratemethod IntStream infiniteEvenNumbers = IntStream.iterate(0, i -> i+2); Iterate returns infinite streams @dgomezg 89 8
  • 75.
    Stream. new iteratemethod IntStream infiniteEvenNumbers = IntStream.iterate(0, i -> i+2); Iterate returns infinite streams Beware of stateful operations: sort(), max(), … @dgomezg 89 8
  • 76.
    Stream. new iteratemethod IntStream infiniteEvenNumbers = IntStream.iterate(0, i -> i+2); Iterate returns infinite streams Beware of stateful operations: sort(), max(), … IntStream evenNumbers = IntStream.iterate(0, i -> i < 500, i -> i+2); IntStream evenNumbers = IntStream.iterate(0, __ -> running, i -> i+2); Better use iterate with hasNext() predicate @dgomezg 89 8
  • 77.
    Stream. ofNullable /** * Returnsa sequential {@code Stream} containing a single element, if * non-null, otherwise returns an empty {@code Stream}. * * @param t the single element * @param <T> the type of stream elements * @return a stream with a single element if the specified element * is non-null, otherwise an empty stream * @since 9 */ public static<T> Stream<T> ofNullable(T t) { return t == null ? Stream.empty() : StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false); } Static method to create an empty Stream in case of null @dgomezg 9
  • 78.
    Stream. Files::lines inparallel Files.lines(Paths.get(“urls.txt")) .parallel() .dropWhile(__ -> !running) .forEach(URLChecker::checkAlive); File::lines was sequential @dgomezg 9
  • 79.
    Stream. Files::lines inparallel Files.lines(Paths.get(“urls.txt")) .parallel() .dropWhile(__ -> !running) .forEach(URLChecker::checkAlive); File::lines was sequential Now it uses Memory mapped files to allow parallelization @dgomezg 9
  • 80.
  • 81.
    Multirelease JAR files Distributionsthat adapt to running environment Useful for libraries and frameworks JAR content root A.class B.class C.class D.class META-INF MANIFEST.MF versions 9 A.class B.class 10 A.class @dgomezg 9
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
    Throwable vs StackWalker.Performance StackTraceElement[] stackTrace = new Throwable().getStackTrace(); StackWalker stackWalker = StackWalker.getInstance(); @dgomezg 9
  • 95.
    Benefits ThreadSafe Simple access (StackWalker.getInstance()) Returnsa stream Filter, assert & skip specific classes Instance of declaring class Limiting depth @dgomezg
  • 96.
  • 97.
    Operations .forEach(System.out::println); .getCallerClass(); .walk(FunctionFunction<? super Stream<StackFrame>,? extends T> function); StackWalker.getInstance() //returns stack depth StackWalker.getInstance().walk(stackStream -> stackStream.count()); //filter only lambdas StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE) .walk(s -> s.map(StackWalker.StackFrame::getMethodName) .limit(10) .filter(methodName -> methodName.contains("lambda")) .count()) @dgomezg 9
  • 98.
    LoggerFactory public class MyLoggerFactory{ public static Logger getLogger() { Class<?> clazz = StackWalker .getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE) .getCallerClass(); return LoggerFactory.getLogger(clazz); } } public class StackWalkerExample { private static Logger LOGGER = MyLoggerFactory.getLogger(); } @dgomezg 9
  • 99.
    Throwable vs StackWalker.performance Microbenchmark by Pierre Laporte https://github.com/pingtimeout/stack-walker-benchmark $ java -jar target/microbenchmarks.jar -f 5 -wi 10 -i 10 [...] # Run complete. Total time: 00:14:52 Benchmark Mode Cnt Score Error Units FileAndLineNumberBenchmark.exception avgt 50 22414.893 ± 456.006 ns/op FileAndLineNumberBenchmark.stackwalkerWithClassAndBCI avgt 50 3699.118 ± 53.813 ns/op FileAndLineNumberBenchmark.stackwalkerWithClassMethodAndBCI avgt 50 6618.887 ± 129.552 ns/op FileAndLineNumberBenchmark.stackwalkerWithExplicitStackTraceElement avgt 50 9043.039 ± 167.530 ns/op FileAndLineNumberBenchmark.stackwalkerWithFileNameAndLineNumber avgt 50 12286.137 ± 377.900 ns/op StackTraceBenchmark.exception avgt 50 21224.342 ± 453.239 ns/op StackTraceBenchmark.stackwalker avgt 50 3573.991 ± 71.692 ns/op @dgomezg 9
  • 100.
  • 101.
    Attributes added to@Deprecated @Documented @Retention(RetentionPolicy.RUNTIME) @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE}) public @interface Deprecated { /** * Returns the version in which the annotated element became deprecated. * The version string is in the same format and namespace as the value of * the {@code @since} javadoc tag. The default value is the empty string. * * @return the version string * @since 9 */ String since() default ""; /** * Indicates whether the annotated element is subject to removal in a * future version. The default value is {@code false}. * * @return whether the element is subject to removal * @since 9 */ boolean forRemoval() default false; } public class Contact implements Comparable<Contact> { @Deprecated(since=“1.1.3”, forRemoval = true) public Period getAge() { return Period.between(getBirth(), LocalDate.now()); } }@dgomezg 9
  • 102.
  • 103.
    Before java 7 publicclass FileReadingJava6 { public static void main(String[] args) throws Exception { BufferedReader br = null; try { String line; br = new BufferedReader(new FileReader(getFile("log4j.xml"))); while ((line = br.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (br != null)br.close(); } catch (IOException ex) { ex.printStackTrace(); } } } @dgomezg < 7
  • 104.
    Java 7 public classFileReadingJava7 { public static void main(String[] args) { try (BufferedReader br = new BufferedReader(new FileReader(getFile("log4j.xml")));){ String line; while ((line = br.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } //br is closed automatically } } @dgomezg 7
  • 105.
    Java 7. Witha provided resource public class FileReaderJava7WithProvidedReader { public void printContents(BufferedReader reader) { try (BufferedReader br = reader){ String line; while ((line = br.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } //br is closed automatically and so, also the reader. } public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new FileReader(getFile("log4j.xml"))); new FileReaderJava7WithProvidedReader().printContents(br); } } 7
  • 106.
    Java 9 public classFileReaderJava9 { public void printContents(BufferedReader reader) { try (reader) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } //reader is closed automatically } public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new FileReader(getFile("log4j.xml"))); new FileReaderJava9().printContents(br); } } @dgomezg 9
  • 107.
  • 108.
  • 109.
  • 110.
    The Unsafe apocalypse sun.misc.Unsafe createobjects without invoking constructors access to direct native memory Intended to be used only by JVM @dgomezg
  • 111.
    The Unsafe apocalypse sun.misc.Unsafe createobjects without invoking constructors access to direct native memory Intended to be used only by JVM but everyone is using it to do ‘cool’ things @dgomezg
  • 112.
    The Unsafe apocalypse sun.misc.Unsafe createobjects without invoking constructors access to direct native memory Intended to be used only by JVM but everyone is using it to do ‘cool’ things Not removed but will be gradually offering alternatives @dgomezg
  • 113.
    VarHandles as alternative classFoo { int i; } Typed reference to variable Abstraction to safe access to a memory location class Bar { static final VarHandle VH_FOO_FIELD_I; static { try { VH_FOO_FIELD_I = MethodHandles.lookup(). in(Foo.class). findVarHandle(Foo.class, "i", int.class); } catch (Exception e) { throw new Error(e); } } } @dgomezg 9
  • 114.
    VarHandles as alternative Fencedoperations CompareAndSwap operations Volatile operations @dgomezg 9
  • 115.
  • 116.
    Strings everywhere. String optimizationto concatenate String.intern() At first only done by compiler (or manually) Then by GC with -XX:+UseStringDeduplication (moved from PermGen to Heap in Java8) String compactation XX:+UsedCompressedStrings optional in Java 6 (uses char[]) XX:+CompactStrings by default on java 9 (uses byte[]) @dgomezg
  • 117.
  • 118.
    The list goeson… • @SafeVarArgs on private instance methods • emoji in source code • UTF-8 in property files • _ not allowed as identifier • Unified JVM logging • Spin-Wait hints @dgomezg
  • 119.
    The list goeson… • @SafeVarArgs on private instance methods • emoji in source code • UTF-8 in property files • _ not allowed as identifier • Unified JVM logging • Spin-Wait hints // This comment is 💩 @dgomezg
  • 120.
    … and on… @dgomezg
  • 121.
  • 122.
    The bright side.Java 9 is more than just Jigsaw • Complements the APIs and from Java8 • Streams • Optionals • Adds new APIs • Reactive streams and Flow API • Improved support for Concurrency and Asyncronous Futures • StackWalker • Improves performance • String computation • G1GC @dgomezg
  • 123.