These are the slides I used for my "Java 9 beyond modularity" at several different local meetups and conferences in Spain during 2017
Java 9 is about to reach its public release scheduled for September 2017. If we ask what are the new features that this new version will include, probably the first that comes to our head is modularity.
But java 9 brings with a lot of features beyound Jigsaw, JPMS or modularity. In this talk we will talk about at least 9 other new features that include this new version of Java that are interesting and maybe will end up being more used than the modularity itself for those who embrace the new version.
Those are changes that come to complement and improve even more the set of new tools (like Streams, Optionals, etc...) that Java 8 brought to us.
We'll take a look at small changes in language syntax (such as new ways of using try-with-resources), changes in Collections APIs and Streams, new tools like VarHandles, new APIs such as the Flow API, and As we allow the inclusion of reactive programming with Java.
Do you want to see in Java 9 beyond modularity? Do you want to have a more complete view of what you can provide? Let's take a look toghether!
5. Jigsaw. Disabling encapsulation constraints.
$java
WARNING: --permit-illegal-access will
be removed in the next major release
@dgomezg
--permit-illegal-access
6. Jigsaw. Disabling encapsulation constraints.
$java
WARNING: --permit-illegal-access will
be removed in the next major release
@dgomezg
--illegal-access=permit
25. Interfaces.Once upon a time…
Back in those days when an interface was a contract
@dgomezg
*
26. 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
*
27. 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
*
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
38. 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
39. Optional. More success than expected
Suitable only for certain use cases
Not as field container
Not as method argument
Not to avoid NPE
@dgomezg
40. 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
41. 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
42. Optional. Initial design problems
the get() design problem
Optional<Contact> emergencyCall = contactBook.getEmergency();
emergencyCall.get().getPhoneNumber();
@dgomezg 8
43. 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
44. 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
45. 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
46. 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
47. Optional. Initial design problems
Avoid isPresent & get —> use ifPresent
Optional<Contact> emergencyCall = contactBook.getEmergency();
emergencyCall.ifPresent(contact -> new PhoneDialer().dial(contact));
@dgomezg 8
48. Optional. Initial design problems
Avoid isPresent & get —> use ifPresent
contactBook.getEmergency()
.ifPresent(contact -> new PhoneDialer().dial(contact));
@dgomezg 8
49. Optional. Initial design problems
Avoid isPresent & get —> use ifPresent
PhoneDialer phoneDialer = new PhoneDialer();
contactBook.getEmergency()
.ifPresent(contact -> phoneDialer.dial(contact));
@dgomezg 8
50. Optional. Initial design problems
Avoid isPresent & get —> use ifPresent
PhoneDialer phoneDialer = new PhoneDialer();
contactBook.getEmergency().ifPresent(phoneDialer::dial);
@dgomezg 8
51. 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
53. Optional. Java 9 improvements
ifPresentOrElse
requires a Consumer<T> and a Runnable
emergencyCall.ifPresentOrElse(
contact -> phoneDialer.dial(contact),
() -> phoneDialer.dial("112"));
@dgomezg
9
54. Optional. Java 9 improvements
ifPresentOrElse
requires a Consumer<T> and a Runnable
emergencyCall.ifPresentOrElse(
phoneDialer::dial,
() -> phoneDialer.dial("112"));
@dgomezg
9
55. 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
56. 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
57. 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
58. 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
59. 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
60. 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
61. 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
62. 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
63. 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
64. 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
66. 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
67. 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
68. 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
69. 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
74. Stream. new iterate method
IntStream infiniteEvenNumbers = IntStream.iterate(0, i -> i+2);
Iterate returns infinite streams
@dgomezg 89
8
75. 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
76. 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
77. 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
78. Stream. Files::lines in parallel
Files.lines(Paths.get(“urls.txt"))
.parallel()
.dropWhile(__ -> !running)
.forEach(URLChecker::checkAlive);
File::lines was sequential
@dgomezg 9
79. 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
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
103. 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
104. 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
105. 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
106. 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
111. 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
112. 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
113. 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
116. 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
118. 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
119. 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
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