#(int x, int y)(x * y)
Versions and Features |
The New World |
Projects To Look Out For |
Slides at slides.codefx.org.
Versions and Features |
The New World |
Projects To Look Out For |
From Java 8 to Java 12.
released 03/2014
free support by Oracle ended 01/2019
free support by Red Hat until 06/2023
n -> lambdas()
Method::references
features.stream()
default method() { … }
led by Brian Goetz
ran from 12/2009 to 02/2014
project page /
JSR 335 /
mailing list (thousands of messages)
launched with a straw-man (12/2009):
#(int x, int y)(x * y)
1st early draft review (11/2011):
Callable<String> c = () -> "done";
2nd review (06/2012) and 3rd review (01/2013)
public review (12/2013) and final ballot (02/2014)
start with an idea
that is then evolved
can take a long time
are fairly open
released 09/2017
support ended 01/2018
module jpms {
requires more.work;
exports migration.challenges;
}
JARs have:
no name the JVM cares about
no explicit dependencies
no well-defined API
no concept of versions
Some consequences:
NoClassDefFoundError
no encapsulation across JARs
version conflicts
Modules are like JARs but have:
proper names
explicit dependencies
a well-defined API
no concept of versions 😭
Important goals:
reliable configuration
strong encapsulation
A file module-info.java
:
module java.sql {
requires transitive java.logging
requires transitive java.xml
uses java.sql.Driver
exports java.sql
exports javax.sql
exports javax.transaction.xa
}
module java.sql {
requires transitive java.logging
requires transitive java.xml
}
Module system enforces:
all required modules are present
no ambiguity
no static dependency cycles
no split packages
module java.sql {
exports java.sql
exports javax.sql
exports javax.transaction.xa
}
Say you want to access java.sql.ResultSet
.
Module system only grants access if:
ResultSet
is public
java.sql
is exported by java.sql
your module reads java.sql
Let’s look at two nifty features:
services
jlink
The module system as a service registry:
module java.sql {
uses java.sql.Driver
}
module mysql.driver {
provides java.sql.Driver
with com.mysql.MySQLDriver;
}
Code in java.sql can do this:
List<Driver> drivers = new ArrayList<>();
ServiceLoader
.load(Driver.class)
.forEach(drivers::add);
Create your own runtime images:
with the JDK modules your app needs
with all modules (JDK, app, deps)
Let’s look at the latter!
# create image
$ jlink
--output awesome-app
--module-path $JAVA_HOME/jmods:mods
--add-modules com.awesome.app
--launcher awesome=com.awesome.app
# [ship image]
# use image
awesome-app/bin/awesome
automatic service binding
(with --bind-services
)
various optimizations
(size and launch performance)
plugin API (not yet public)
cross OS image generation
finer grained dependencies and exports
open packages and modules (for reflection)
unnamed and automatic modules (for migration)
layers (for containers)
I’ve written a book!
E-book available ⇝ tiny.cc/jms
creating, building,
running modules
migration to Java 9+
modularization
services and
advanced features
reflection and layers
custom runtime images
led by Mark Reinhold
ran from 12/2008 to 09/2017
Sun’s primary goal in the upcoming JDK 7 release will be to modularize the JDK […], which we hope to deliver early in 2010.
😊
Java 9 release was planned for 09/2016
Jigsaw delays it to 03/2017,
then 07/2017, then 09/2017
public review ballot (05/2017)
public review ballot fails (05/2017)
various fundamental changes requested;
only change: encapsulation turned off
reconsideration ballot passes (06/2017)
¯\_(ツ)_/¯
can lead to very heated discussions
are subject to politics
take feedback into account and
adapt to new requirements
are not as open as they could be
can take a very long time and
delay Java releases
released 03/2018
support ended 07/2018
local-variable type inference:
var users = new ArrayList<User>();
application class-data sharing (hardly)
We’re used to duplicating
type information:
URL codefx = new URL("http://codefx.org");
URLConnection connection = codefx.openConnection();
Reader reader = new BufferedReader(
new InputStreamReader(
connection.getInputStream()));
Not so bad?
What about this?
No no = new No();
AmountIncrease<BigDecimal> more =
new BigDecimalAmountIncrease();
HorizontalConnection<LinePosition, LinePosition>
jumping =
new HorizontalLinePositionConnection();
Variable variable = new Constant(5);
List<String> names = List.of("Max", "Maria");
Can’t somebody else do that?
Compiler knows the types!
Enter var
:
var codefx = new URL("http://codefx.org");
var connection = codefx.openConnection();
var reader = new BufferedReader(
new InputStreamReader(
connection.getInputStream()));
var
var
only works in limited scopes:
compiler infers type from right-hand side
⇝ rhs has to exist and define a type
only works for local variables, for
, try
⇝ no var
on fields or in method signatures
also on lambda parameters ⑪
⇝ annotate inferred type on lambda parameters
var
Two more:
not a keyword, but a reserved type name
⇝ variables/fields can be named var
compiler writes type into bytecode
⇝ no run-time component
This is about readability!
less redundancy
more intermediate variables
more focus on variable names
aligned variable names
var no = new No();
var more = new BigDecimalAmountIncrease();
var jumping = new HorizontalLinePositionConnection();
var variable = new Constant(5);
var names = List.of("Max", "Maria");
Still think omitting types is always bad?
Ever wrote a lambda without declaring types?
rhetoricalQuestion.answer(yes -> "see my point?");
var
Blog post:
First Contact With var
In Java 10
Video:
var
cheat sheet (⇜ print when getting started!)
var
and …
More on that later!
released 09/2018
free support by Oracle ended 01/2019
free support by Red Hat until 10/2024
Err…
single-source-file execution and scripts:
java HelloWorld.java
Epsilon GC
Compiling and running
simple Java programs is verbose.
Not any more!
java HelloJava11.java
How it works:
compiles source into memory
runs from there
Details:
requires module jdk.compiler
processes options like class/module path et al.
interprets @files
for easier option management
Mostly similar to jshell
:
easier demonstrations
more portable examples
experimentation with new language features
(combine with --enable-preview
)
But also: script files!
Steps towards easier scripting:
arbitrary file names
shebang support
Use --source
if file doesn’t end in .java
:
java --source 11 hello-java-11
To create "proper scripts":
include shebang in source:
#!/opt/jdk-11/bin/java --source 11
name script and make it executable
execute it as any other script:
# from current directory:
./hello-java-11
# from PATH:
hello-java-11
no language changes
no monumental dev-facing features
this will become common
that’s not a bad thing!
release 03/2019
support ends 07/2019
preview on switch expressions:
DayOfWeek day = // ...
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};
Note:
In Java 12, switch expressions are
a preview language feature!
must be enabled with --enable-preview
(on javac
and java
).
in IntelliJ 2018.3 or later, set the module’s
language level to 12 (Preview) - Switch expressions
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};
Two things to note:
switch
"has a result"
⇝ it’s an expression, not a statement
lambda-style arrow syntax
Statement:
if (condition)
result = doThis();
else
result = doThat();
Expression:
result = condition
? doThis()
: doThat();
Statement:
imperative construct
guides computation, but has no result
Expression:
is computed to a result
For switch
:
if used with an assignment,
switch
becomes an expression
if used "stand-alone", it’s
treated as a statement
This results in different behavior.
You can use :
and ->
with
expressions and statements, e.g.:
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY: break 6;
case TUESDAY: break 7;
case THURSDAY, SATURDAY: break 8;
case WEDNESDAY: break 9;
};
switch
is used as an expression
break result
returns result
in ⑬ break
becomes yield
Whether you use arrow or colon
results in different behavior.
general improvements
multiple case labels
specifics of arrow form
no fall-through
statement blocks
specifics of expressions
poly expression
returning early
exhaustiveness
Video:
No, even later…
release 09/2019
support ends 01/2020
preview on text blocks:
String html = """
<html>
<body>
<p>"Hello, text blocks!"</p>
</body>
</html>
"""
String html = """
<html>
<body>
<p>"Hello, text blocks!"</p>
</body>
</html>
"""
open with """
and newline
close with """
on same or own line
regular escaping (not raw!)
single "
needs no escape, though
indentation determined by closing """
I said later!
Versions and Features |
The New World |
Projects To Look Out For |
OpenJDK is the default
(not Oracle JDK)
major release every 6 months
(not every 2-5 years)
only selected versions get LTS,
(not all of them)
OpenJDK is Java’s reference implementation:
a project
a code base
It doesn’t ship binaries, but others do:
Oracle on jdk.java.net
AdoptOpenJDK on adoptopenjdk.net
Sun/Oracle JDK used to…
contain more features
be perceived as more stable
be perceived as more performant
As of Java 11, on a technical basis,
Oracle JDK and OpenJDK are identical.
*
Only difference is license and support model:
Oracle’s OpenJDK: licensed under GPL+CE
Oracle JDK is fully commercial:
from 11 on, no free use in production
⇝ OpenJDK is the new default!
(More on support later…)
The old plan:
releases are driven by flagship features
new major release roughly every 2 years
The old reality:
Java 7 took 5 years
Java 8 took 3 years
Java 9 took 3.5 years
"Bump an 'almost ready' feature
2+ years into the future?"
⇝ "Better to delay the release."
implemented features provide no value
increases reaction time
puts (political) pressure on projects
makes everybody grumpy
If it hurts, do it more often.
fixed six-month release cadence
(March and September)
ship everything that is ready
All are major releases
with known quality guarantees.
⇝ No "beta versions"!
completed features get out earlier
no pressure to complete features on time
easier to react to changes in the ecosystem
easier to incubate features
Two concepts allow features to incubate:
Features are shipped for experimentation.
There are safeguards against accidental proliferation.
To discuss long-term support,
lets look at JDK development:
there’s the OpenJDK code base at
hg.openjdk.java.net/jdk/jdk/
there are many clones:
for each JDK release
for each JDK project
each vendor has their own
A new feature, simplified:
developed in "feature branch"
merged into "master" when (nearly) finished
A release, simplified:
"release branch" created 3 months prior
only bug fixes merged to "release branch"
A bug/security/etc fix, simplified:
usually developed in "master"
merged into relevant release branches
Support really means:
fixing bugs, usually in "master"
merging fixes to "release branches"
How does Oracle handle that?
work on "master" in OpenJDK
merge to current "release branch" in OpenJDK
merge to LTS version in Oracle JDK
What’s left for long-term support?
⇝ Merging fixes into old JDK versions.
Long-term support for OpenJDK:
commitment by the community:
4+ years for 8, 11, 17, 23, etc.
for OpenJDK 8 until 06/2023
for OpenJDK 11 until 10/2024
built and shipped by Adopt OpenJDK
Other players:
More?
Amazon Corretto:
builds on OpenJDK
contains additional security
and stability fixes by Amazon
It is updated quarterly:
Java 8 until at least 06/2023
Java 11 until at least 08/2024
"Java will change too fast."
"Test matrix will explode."
"Ecosystem will fragment."
"Constant migrations will be expensive."
"Nobody will leave Java 11 behind."
The rate of innovation doesn’t change. The rate of innovation delivery increases.
Maybe speed will pick up a little:
recent activities target low-hanging fruits
Oracle is focusing on Java core (my impression!)
By and large:
Evolution will be steadier, not faster.
(see Java 10 - 12)
As the range of supported versions increases…
builds need to run against all of them
developers need to switch between them
Many tools already support this.
⇝ We need to know how.
Also: Moar automization!
"This will be like Python 2/3!"
No.
But not the norm:
Java 10 is trivial
Java 11 is easy
Java 12 is trivial
Oracle is still committed
to backwards compatibility!
Balance shifted between
compatibility vs evolution:
@Deprecated(forRemoval=true)
"one major release" is now 6 months, not 36
increasing bytecode level
incubating features (if used inappropriately!)
Remedies:
stick to supported APIs
stick to standardized behavior
stick to well-maintained projects
keep dependencies and tools up to date
I’d love for everyone
to always be up to date.
But:
Going from Java 11 to 12
is not without risks.
😢
Lack of support for 12-16:
free support is very unlikely
commercial support is rare
(Azul offers MTS for 13 and 15)
Without support, you have to upgrade
to each major version immediately!
What could possibly go wrong?!
Before you upgrade to Java 12:
read Should you adopt Java 12 […]?
by Stephen Colebourne
take a coffee break
understand that most risks
come from building against 12
be content that all you need
to upgrade is run on 12
What could possibly go wrong?!
remember @Deprecated(forRemoval=true)
?
changes to unsupported APIs, e.g. Unsafe
Problems are not likely,
but usually hard to predict.
⇝ Chance is low.
If an upgrade fails,
you have two choices:
run on an unsupported (unsecure) JVM 😮
downgrade to recent LTS 😱
⇝ Damage is potentially enormous.
expected_damage = chance * damage
Consider this:
more up-to-date ⇝ lower chance
fewer dependencies ⇝ lower chance
smaller code base ⇝ smaller damage
find a suitable upgrade cadence
build on each release (including EA)
only rely on standardized behavior
heed deprecation warnings (jdeprscan
)
keep dependencies and tools up to date
Most importantly:
Be aware of what’s coming!
Versions and Features |
The New World |
Projects To Look Out For |
Many great features on the horizon!
Don’t focus on versions!
Focus on projects and JEPs:
Let’s have a look at what’s coming!
(Straw-man syntax ahead!)
Amber: smaller, productivity-oriented features
Valhalla: generic specialization and value types
Loom: fibers and continuations
Metropolis: Graal and ahead-of-time compilation
Panama: improved interaction with non-Java code
Smaller, productivity-oriented Java language features
Profile:
led by Brian Goetz
project /
wiki /
mailing list /
talks:
0,
1,
2 /
inofficial early access builds
launched March 2017
Java compared to more modern languages:
can be cumbersome
lacks expressiveness
tends to require boilerplate
Amber wants to improve that situation!
pattern matching (JEP 305)
records (JEP draft)
serialization revamp (white paper)
concise method bodies (JEP draft)
raw string literals (maybe)
Object value = // ...
String formatted = switch (value) {
case Integer i -> String.format("int %d", i);
case Byte b -> String.format("byte %d", b);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> "unknown " + value.toString();
};
Yeah:
more powerful conditions
no repetition between condition and block
public int eval(Node n) {
return switch(n) {
case IntNode(int i) -> i;
case NegNode(Node n) -> -eval(n);
case AddNode(Node left, Node right) ->
eval(left) + eval(right);
};
}
Yeah:
deconstructing complex objects
goodbye visitor pattern!
public record Range(int low, int high) {
// compiler generates:
// * constructor, deconstructor
// * equals/hashCode/toString
// * accessors low(), high()
}
Yeah:
no boilerplate for plain "data carriers"
no room for error in equals
/hashCode
makes Java more expressive
The API for a record models the state, the whole state, and nothing but the state.
The deal:
give up encapsulation
couple API to internal state
get API for free
public record Range(int low, int high) {
// compiler knows signature and assigns to fields
public Range {
if (low > high)
throw new IllegalArgumentException();
}
public void setLow(int low) {
if (low > this.high)
throw new IllegalArgumentException();
this.low = low;
}
}
Serialization is hell:
complicates every JDK feature
repeated security vulnerabilities
uses "invisible" mechanisms
The JDK team wants to get rid of it!
Replacement may look as follows:
only works with records
deconstructs a record graph
passes data to serilization engine
one engine per format:
XML, JSON, YAML, …
Yeah:
records are a great fit for serialization
new mechanism uses (de)constructors
superior maintainability
class ListWrapper<E> implements List<E> {
private List<E> list;
public int size() -> list.size();
public T get(int index) -> list.get(index);
public int indexOf(E el) = list::indexOf;
}
Yeah:
simple methods get simple code
fewer (empty) lines
String regex = \"\+(\d*[.])?\d"
Yeah:
no escaping of special characters
But:
was planned as preview in Java 12
removed last minute
Turns out, it’s complicated. 😁
Maybe?
String yaml = \"""
name: "Positive number"
regex: "\+(\d*[.])?\d"
""";
Makes Java more expressive:
type inference with var
⑩
switch expressions ⑫
text blocks ⑬
pattern matching
records
serialization revamp
concise method bodies
raw string literals
Advanced Java VM and Language feature candidates
Profile:
led by Brian Goetz and John Rose
project /
wiki /
mailing list /
talks:
0,
1,
2 /
official early access builds
launched July 2014
In Java, (almost) everything is a class:
mutable by default
memory access indirection
requires extra memory for header
allows locking and other
identity-based operations
Wouldn’t it be nice to create a custom int
?
public value Range {
// implicitly final
private int low;
private int high;
// you write:
// * constructor, static factories
// * equals/hashCode/toString
// * accessors, etc.
}
public value Range {
private int low;
private int high;
}
Yeah:
enforced immutability
no memory indirection! (flat)
no Object
header! (dense)
makes Java more expressive
Codes like a class, works like an
int
.
The deal:
give up identity / mutability
(and self references)
get flat and dense memory layout
no identity / mutability
⇝ flat and dense memory layout
no encapsulation
⇝ less boilerplate
Might be combinable to "value records".
When everybody creates their own "primitives",
boxing becomes omni-present and very painful!
List<int> ids = new ArrayList<>();
Yeah:
backed by an actual int[]
great performance
works with your value types
Value types and generic specialization together,
have immense effects inside the JDK!
no more manual specializations:
functional interfaces
stream API
Optional
API
better performance
Value types and generic specialization together,
have immense effects on your code!
fewer trade-offs between
design and performance
better performance
can express design more clearly
more robust APIs
Makes Java more expressive and performant:
value types
primitive specialization
Fibers, delimited continuations, explicit tail-call
Profile:
led by Ron Pressler
project / wiki / mailing list / talks: 0, 1
launched January 2018
Imagine a hypothetical request:
interpret request
query database (blocks)
process data for response
JVM resource utilization:
good for tasks 1., 3.
really bad for task 2.
How to implement that request?
thread per request
blocks on certain calls
bad thread utilization
use non-blocking APIs with futures
incompatible with synchronous code
great thread utilization (scalable!)
A fiber:
looks like a thread to devs
low memory footprint ([k]bytes)
small switching cost
scheduled by the JVM
The JVM manages fibers:
runs them in a pool of carrier threads
makes fibers yield on blocking calls
(frees the carrier thread!)
continues fibers when calls return
Remember the hypothetical request:
interpret request
query database (blocks)
process data for response
In a fiber:
JVM submits fiber to thread pool
when 2. blocks, fiber yields
JVM hands thread back to pool
when 2. unblocks, JVM resubmits fiber
fiber continues with 3. (how?)
Yeah:
great thread utilization
code is written/debugged as if synchronous
legacy code may be forward compatible
How do fibers continue?
use continuations (low-level API)
JVM stores and restores call stack
Makes threading more pleasant:
simple programming model
great thread utilization
To know what’s coming:
pick a project that interests you
look out for mentions
subscribe to the mailing list
find early access builds and try them
give feedback
Tell your colleagues about it!
💻 codefx.org
🐦 @nipafx
Slides at slides.codefx.org
⇜ Get my book!
You can hire me:
training (Java 8-12, JUnit 5)
consulting (Java 8-12)