Java 10 - ashishranjandev/developer-wiki GitHub Wiki
Traditionally, Java's major releases were feature-driven, often leading to delays due to the complexity of integrating big features like Lambdas in Java 8 and the Modular system in Java 9. These delays made Java lag behind other languages in terms of release frequency. To address this, Mark Reinhold proposed a two-year release cycle in 2012, aiming for more predictable updates. However, delays persisted, with Java 9 releasing in 2017, much later than expected due to the complexity of the Modular system.
In 2017, Reinhold introduced a more aggressive, time-based release model, with new Java versions planned every six months, starting with Java 10 in March 2018. This shift from feature-driven to time-based releases marks a significant change in Java's release strategy, allowing for more frequent updates and faster innovation. However, this rapid release cycle raises concerns about maintaining support for each version, as developers generally prefer to use supported versions that receive regular security updates. By 2028, this model could result in Java 31, highlighting the significant acceleration in Java's development and the challenges of managing frequent major releases.
Oracle's new release schedule for Java, introduced in 2017, shifted from feature-driven releases to a time-based model, with a new version released every six months. This change aimed to increase the agility of Java’s development, allowing features to be released as soon as they’re ready, rather than delaying entire releases for incomplete features. However, this more frequent release cycle can be challenging for organisations, as it may seem like they are forced to upgrade their Java environment every six months, which could be difficult in certain operational settings.
To alleviate this, Oracle introduced the concept of Long-Term Support (LTS) releases, designating a specific Java version as LTS every three years. LTS releases, such as Java 11, Java 17, and the upcoming Java 23, receive security updates and extended support, providing a stable option for organizations that prefer not to update frequently. This approach allows companies to choose between adopting every Java release or focusing on the more stable LTS versions.
However, sticking exclusively to LTS versions comes with risks. Developers might miss significant changes or deprecations that occur in non-LTS releases, leading to technical debt. It’s recommended to use the latest Java versions in development and testing environments, ensuring compatibility and addressing potential issues early. This can be done while maintaining LTS versions in production environments for stability. The introduction of the --release
flag in Java 9 helps developers compile code on the latest Java version while targeting an older LTS version, balancing the need for innovation with the need for production stability.
This new release strategy has made Java more dynamic and responsive to technological advancements, though it requires adjustments in how teams manage updates and technical debt. The success of this approach will be determined in the coming years.
The Oracle JDK always builds off of OpenJDK itself, but adds additional closed-source features. You can think of for example alternative garbage collection implementations, closed-source rendering engine for GUI applications.
Oracle has committed to open source all the commercial features that are part of the Oracle JDK and to contribute them to Open JDK.
- Java Flight Recorder
- Java Mission Control
- Z Garbage collector - For large Heaps
- Application Class Data Sharing - Done in JDK 10.
Builds available for 64-bit
- Mac
- Linux
- Windows
No release by oracle for ARM and 32 - bit.
Other vendors can be relied
- Azul
- AdoptOpenJDK
- IBM
One remaining challenge is the inclusion of root certificates necessary for secure connections, which have traditionally been tied to Oracle through agreements with certificate authorities.
For establishing secured connections the certificates should be present in the cacerts folder. Oracle JDK has them but OpenJDK do not. Oracle is working to transfer this root CA program to OpenJDK, but the process requires new agreements and will take time. As of OpenJDK 10, some certificates are already included, but full integration is ongoing. Progress can be tracked here: https://openjdk.java.net/jeps/319
Removals
- javah -> javac -h
- policy tool -> text editor
- -X:prof -> profiling tool -> jmap
Deprecations
- java.security.acl -> java.security
- java.security.Certificate,Signer,Identity,IdentityScope
- javax.security.auth.Policy -> java.security.Policy
// Java can infer the variable type is String
var bookName = "Head First";
// Code looks cleaner, much less to type
// type is already clear from right hand side
var openJDKURL = new URL("https://openjdk.java.net");
var connection = openJDKURL.openConnection();
var openJDKStream = new BufferedInputStream(connection.getInputStream());
// Where not to use
// Getting the type would be difficult for code reader
//var result = aService.findResult();
//var is not a keyword, it is reserved type name
//for backward compability for codes using it as identifier
var var = "var";
Does this make Java dynamically type language? No.
Even though we don't put the type explicitly into the source code anymore when using var, the type is still there.
It's only inferred by the compiler instead of us typing it.
int counter = 0;
counter += 1;
0: iconst_0
1: istore_1
2: iinc
var counter = 0;
counter += 1;
0: iconst_0
1: istore_1
2: iinc
Type inference is not new in java
List<Integer> integerList = new ArrayList<>();
List<Integer> emptyList = Collections.emptyList();
Predicate<String> predicate = str -> str.length() > 3;
// This does not compile as java cannot infer with given information
var predicate = str -> str.length() > 3;
// This won't compile as well
var predicate = (String str) -> str.length() > 3;
There reason for this is that lambdas always map back to a so-called single abstract method interface, which is an interface definition containing a single method where the parameters of the method correspond with the parameters of the lambda, and also the return type of the methods in the interface corresponds to the return type of the lambda. Now, Predicate happens to be searching single abstract method interface. But who knows? There might be many more interfaces containing a single method, taking a string, and returning a Boolean, and which one should the compiler pick? It doesn't know.
// This works -> ArrayList<Object> would be created
var myList = new ArrayList<>();
// If we have to use var
var myList = new ArrayList<String>();
Not recommended to use in
- method types
- return types
- field types
- catch blocks
Because based on the invocations the compiler with infer the type to be superclass of all invocations. Any new invocation can change the type to a new superclass leading to caller changing the behaviour.
// Won't compile
var empty = null;
// anonymous class, Object$1 extends Object would be used
var obj = new Object() {};
// This assignment would not work
obj = new Object();
// Intersection types
// the type of list will be <? extends Serializable and Comparable<>>
var list = List.of(1, 2.0, "3");
When full GC is required, In Java 9 G1GC was still using serial full GC which used single thread. When full GC is required, In Java 10 G1GC will use parallel full GC which used multiple thread.
We can configure number of threads with -XX:ParalleGCThreads .
- Improve VM startup time - VM loads faster
- Reduce memory footprint
- Shared library of class metadata - Different runs of same JVM - Results can be persisted in shared library and memory mapped later
- Earlier it System Classes only - now can be used for application classes as well
- Class path should be identical
graph TD
%% Start of the process
A[Start] --> B[Class Referenced for the First Time]
%% Loading phase
B --> C[Loading]
C --> D[ClassLoader Loads .class File]
D --> E[Bytecode Loaded into Memory]
%% Linking phase
E --> F[Linking]
F --> G[Verification]
G --> H{Verification Success?}
H -->|Yes| I[Preparation]
H -->|No| J[Throw VerifyError]
%% Preparation phase: Static fields are initialized to default values
I --> K[Resolution -Optional]
%% Initialization phase: Static fields and initializers are set up
K --> L[Initialization]
L --> M[Static Fields Assigned Non-default Values]
M --> N[Execute Static Initializers]
%% Class is ready for execution
N --> O[Class Ready for Use]
O --> P[Program Execution Continues]
JVM -> java -Xshare:dump -> classes.jsa -> binary file
- -Xshare:dump
- -XX:+UseAppCDS
- -XX:ShareClassListFile=
- -XX:SharedArchiveFile=myapp.jsa
How to create class list file?
-XX:DumpuploadedClasslist=myapplist
## This does not work for custom class loaders
- Java can now detect containers.
- Earlier it used to query host OS for resources and set its limit accordingly.
- Java can query container instead of host OS for resources and set its limit accordingly.
- Previously it was hard to attach, for example, diagnostic commands to the JVM because it was running in an isolated process namespace inside of a container. In Java 10 it's now possible to attach to the Java process from the Host OS.
- Only for Docker and Linux
We can overwrite
- -XX:ActiveProcessorCount
- -XX:InitialRAMPercentage
- -XX:MaxRAMPercentage
- -XX:MinRAMPercentage