It was Tuesday, May 23, 1995 when Sun Microsystems, Inc. released the first version of Java as Java Development Kit 1.0 (JDK 1.0). Back then, the Java programming language already included the software development environment (JDK) for creating Java applications and a Java Virtual Machine (JVM) for running Java programs on any device and operating system. Thus the slogan “Write once, run anywhere” was born. The Java Standard Edition (Java SE) still consists of the combination of JDK and JVM and is generally referred to as “Java”.
Platform independence and backward compatibility
What began with the familiar abilities of an object-oriented programming language has been continuously expanded by successively adding new features to the Java APIs with class libraries. With the interpreted language approach, the Java compiler generates the bytecode for the JVM and the Java interpreter executes a Java application’s compiled bytecode. Due to Java bytecodes’ platform independence, Java programs can run on any supported operating system for which a JVM exists.
Java’s spread was facilitated by the heterogeneous system landscape at the time and emerging networking. In order to actually write portable Java programs, all Java API platform dependencies were avoided by developing 100 percent pure Java programs that were certified for portability by Sun’s Pure Java program certification. The Java APIs constant renewal, with backward compatibility guaranteed at the same time, allowed Java to run older, uncompiled programs directly on a current Java version. The Java compiler was only triggered when new Java features were used and existing programs gradually modernized.
The 30-year journey (Fig. 1) into a modern Java application landscape was shaped by intensive code reviews and thoroughly evaluating new Java features in each major release.
Fig. 1: Java roadmap
The journey continues
Java’s next developmental phase includes enhancements in code reflection, ahead-of-time (AOT) compilation and optimizing 8-byte object headers. Additionally, efforts are focused on finalizing the APIs for Structured Concurrency and Scoped Values. Java’s expansion plans aim to boost performance in the Foreign Function & Memory API, further develop AOT compilation and complete the Structured Concurrency API. The OpenJDK community’s broader ambitions are centered around extension projects such as Amber, Babylon, Leyden, Lilliput, Loom, Valhalla, and Panama.
Project Amber takes care of smaller, production-related Java language functions to submit as JDK Enhancement Proposal (JEP) candidates in the OpenJDK JEP process.
Project Babylon aims to extend the reach of Java to foreign programming models as SQL, differentiable programming (merging the algorithmic domains of machine learning and numerical optimization), machine learning models, and GPUs. Babylon intends to achieve this with an extension to Java Reflective Programming called Code Reflection. Plans for the Babylon project include preparing to incubate code reflection, working on HAT (Heterogeneous Accelerator Toolkit) and researching an ONNX runtime script prototype equivalent in Java.
Project Leyden (JDK static image concept) focuses on improving start-up time, reaching peak performance faster and reducing Java programs space requirements. This includes AOT method profiling and AOT code compilation.
Project Lilliput examines techniques to reduce the Java Object Header in Hotspot JVM from 128 bits to 64 bits or less. Initially, the goal was to reduce the object header to 64 bits. A reduction to 32 bits may be possible as a secondary goal. But the overall goal is to clear ten to 20 percent of the heap memory.
Project Loom develops JVM functions and APIs that support lightweight concurrency and new programming models. The Structured Concurrency API and the Scoped Values API are to be completed within this project.
The Valhalla project focuses on the Java object model extension. The development works on Value Types (Preview), Null-Checked Types and a first improvement of Numerics and Primitives.
Project Panama intends to achieve better developer support for the interaction between JVM and native code. Connections between the JVM and the well-defined non-Java interfaces (Foreign APIs) have been revised for this – in particular, the APIs that are typically used by C programmers. This includes the Vector API, performance improvements to the Foreign Function & Memory API, the Record Mapper, and improvements to the jextract tool for generating Java bindings.
Learn more about JAX LondonSTAY TUNED!
Access to C/C++ libraries and foreign memory
Java’s introduction created the need to access libraries and foreign memory written in different languages, especially for those developed with C/C++. The Java platform offers the Java Native Interface (JNI) for access. With JNI, applications can include native code written in languages like C/C++ alongside Java code. From the Java platform perspective, the JNI API enables the integration of legacy code and the solution for interoperability issues between Java code and natively compiled code (Fig. 2). Memory operations can be problematic because native code is run, used objects must be re-released and the Java application is directly returned to native calls without being able to recognize errors in the native code.
So far, the following steps had to be implemented with JNI:
- Write and compile a Java program
- Generate header file from Java class
- Write a C program
- Generate C program as dynamic or shared library file
- Load dynamic library or shared library
- Run Java program that runs the C program via JNI
Fig. 2: Java application launch from native C/C++ code via JNI
Jextract generates Java bindings
Jextract automatically generates Java bindings from native library headers, which provides convenience because the Java bindings don’t have to be created from the source code. The tool is targeted at experienced users. The jextract development tool is not included in the JDK, but is part of the code tools. It is delivered separately with the jextract Early-Access Builds project. The jextract tool, which strictly speaking isn’t part of the runtime-related Foreign Linker API, simplifies development considerably by generating Java classes from the C header files (Fig. 3). Thereby the underlying details of the Foreign Linker API are hidden by jextract.
Jextract is a simple but convenient tool that generates a Java API from one or more native C headers. Interacting with the jextract tool involves two steps:
- Generating the Java interface for the C header files with jextract
- Writing a Java program that calls the wrapper API points generated by jextract
Fig. 3: Java application call of native C/C++ code with jextract
Panama projects long-term plans to implement the Foreign-Function & Memory API, the Vector API and the Jextract tool are taking shape. These interfaces enable and simplify type-safe access to native libraries. Conveniently, they also support the use of familiar abstraction classes like Bytebuffer. Compared to JNI, development times are shortened by reducing access barriers. Using additional native functions can potentially lead to increased security. The new APIs are at a higher level and offer better options for integrating an external library into Java development projects using the jextract tool. This makes integrating C/C++ code into an existing Java project much easier. Nevertheless, it needs the maturity and stability to replace the JNI calls long-term and to use any 3rd party code.
Looking back at functional programming with Lambdas
Introducing Lambda expressions and the Stream API in March 2014 was Java SE 8’s biggest language change since the introduction of generics in Java SE 1.5, enabling functional programming for Java while ensuring maximum backwards compatibility. Lambda expressions were incorporated into Java language syntax and implemented through invokedynamic bytecode. The Lambda language feature changed the way Java programs are written. Functional concepts were finally incorporated into Java SE 8. From today’s perspective, Lambdas with the Stream API are vital for modern Java applications.
Generally, a Lambda represents a function and a Lambda expression is a functional interface instance. However, the Lambda expression doesn’t contain any information about which functional interface it’s implementing. This information is derived from context. A function is similar to a calculation that is given a number of parameters and then returns a value, making it more of a mathematical concept rather than a method.
Functions can have side effects, so it was important to avoid these when implementing Lambda expressions in Java SE 8. The main point is to calculate the input parameters and return a result. Before Java SE 8, every calculation had to be contained in a method, which was contained in a class. A method call is performed via a name reference, optionally including the method’s class or an instance linked to that class. As a result, functions in Java could previously only be implemented using methods.
With Lambdas in Java SE 8, you get functions that aren’t necessarily linked to a method name within a specified class. If the function is released from the strict constraints of method name and class, you can use a Lambda function and pass it on as a parameter, return it as a return value or integrate it into a data structure. As a result, you can use functions with Java, just like in other programming languages. Functions can be nested inside each other and return functions. Many developers are currently using Lambdas with the Stream API in their Java application projects.
Housekeeping project Jigsaw modularizes Java
JDK 9, released in September 2017, contained the modular structure of Java SE with the Java platform module system. This made it possible to personally determine the technical packaging of selected Java functionality. The Jigsaw project primarily sought to provide the design and implementation of a standard module system for the Java platform and JDK 9. The goal was to make it user-friendly so developers could use the module system to build and maintain libraries for large, scalable Java SE applications Java SE 9 can be used on the target platforms of installed devices, laptops, desktops and servers.
The jdeps tool is used to perform the module dependency analysis in JDK. Additionally, dependent modules with a special classpath dependency can be listed. The jlink tool creates an individual Java runtime, which is considerably smaller than a complete Java runtime environment with a complete JDK, including the created Java application. Modularizing the Java SE platform in JDK 9 has both advantages and major changes. Existing application code that only uses official Java SE platform APIs with the supported JDK-specific APIs should continue to be executable without changes. Backward compatibility for previous major Java SE versions was and still is ensured. This also applies to future JDK releases with the Java module system. Jigsaw separates the APIs and the Java component implementation and offers better support with this modularization model for large Java projects. Implementing Java application modularization was designed for the long run and the classpath can still be used.
GraalVM: the Booster in Java’s ecosystem
With its multilingualism, JIT compiler and native image, GraalVM gave the Java ecosystem an innovation boost in 2019. GraalVM offers a great opportunity for developers and users to potentially change the Java landscape entirely. The GraalVM is a virtual machine (VM) and a high-performance Java Development Kit (JDK) for applications written in the JVM-based programming languages Java, Scala, Kotlin, Clojure, the dynamic languages JavaScript, R, Ruby, Python and the LLVM-based languages C/C++. GraalVM can run Java applications in two ways, on the HotSpot JVM with the Graal Just-in-Time (JIT) compiler or as a pre-compiled native executable in Ahead-of-Time (AOT) mode.
GraalVM’s multilingual capabilities combine different programming languages in a single application. This enables language interoperability in a common runtime environment. The GraalVM can be used either as an open source community edition (CE) or as an Oracle GraalVM with the “GraalVM Free Terms and Conditions (GFTC)” license.
GraalVM was originally developed at Oracle Labs several years ago, leading to the first GraalVM version ready for series production in May 2019. It fits seamlessly into the Java ecosystem and provides a multilingual home for programming languages equipped with a bytecode compiler. Besides the performance improvements and polyglot support (Fig. 4), GraalVM removes the limits between programming languages and supports interoperability in a shared runtime environment.
Fig. 4: HotSpot VM with Graal for JVM languages and dynamic languages
GraalVM Native Image
With GraalVM, native images can be generated and the native binaries are executed directly in the operating system without having to use the JVM. The executable file contains the application classes, dependent classes, runtime library classes and statically linked native code of the JDK. The binary file does not run on the Java VM, but contains necessary components such as memory management, thread scheduling and other parts of another runtime system called “Substrate VM”. The Substrate VM contains the runtime components De-Optimizer, Garbage Collector, Thread Scheduling and further components.
During native image generation, a static analysis is applied to find any code that is accessible via the Java main method. Afterwards, a full AOT compilation is carried out. Under the conditions of a defined and closed environment, executable images or shared objects are created through an iterative analysis of Java applications, libraries and JDK using optimized AOT compilation. The resulting native file binary contains the entire application for standalone execution in machine code. The native binary can be linked to other native applications and optionally include the GraalVM compiler for additional JIT compilation support to run other GraalVM-based languages.
To enhance performance, native images can be created with profile-guided optimizations (PGO) based on data collected from a previous application run. Compared to a JVM, the GraalVM Native Image offers faster startup times and lower memory consumption relative to runtime. The creation of the GraalVM Native Image binary must explicitly take place on the selected operating platform for the respective operating system Linux, MS Windows or macOS and cannot be created cross-platform (Fig. 5).
Fig. 5: GraalVM Native Image, iterative analysis and binary generation
GraalVM Use Cases
After the initial excitement over GraalVM’s innovative capabilities and its broad application possibilities, its productive use has been demonstrated in various projects. The GraalVM AOT compiler, which generates independently executable native images with significantly faster start-up times and lower memory consumption, provides a considerable advantage, especially with the Spring Boot 3.x and microservices frameworks Quarkus, Helidon, and Micronaut. GraalVM native images are also fitting for applications deployed via container images. They are particularly interesting in combination with “Function as a Service (FaaS)” platforms. In AWS Lambda, which can scale quickly to millions and scale down to zero when not in use, the combination of GraalVM native images and instant execution speed is a perfect fit GraalVM’s reduced memory requirements are especially appealing when used with AWS Lambda, as cloud resource consumption is billed based on the AWS Lambda memory size.
Local Large-Language-Models (LLM) with Java and GraalVM
Implementing a fast LLM inference engine in modern Java allows for local execution of the Java LLM engine. To optimize performance for the best processor efficiency, the Java Vector API, Foreign Function & Memory API, and GraalVM AOT technology were combined. The Foreign Function & Memory API enables interoperability between Java and native code. It works with Graal JIT and is experimentally supported in GraalVM Native Image via -H:+ForeignAPISupport for up-and-down calls and foreign memory access. The Java Vector API allows fast vector calculations, first supported in GraalVM for JDK 21 and is compatible with GraalVM Native Image.
Faster LLM inference with GraalVM Native Image reaches JIT speed using AOT, which is especially beneficial for the inference code. By pre-parsing the GGUP metadata and caching prompts at build time, Java’s native performance enables the immediate execution of the first token in under 25 ms. This means that with AOT and a pre-loaded model, the first token is executed instantly. The integration of Java with GraalVM AOT technology was experimentally implemented with LangChain4j to enable faster LLM inference with GraalVM.
JDK Features and OpenJDK
Since Oracle JDK 11’s introduction in September 2018, the technical differences between Oracle JDK 11 and Oracle OpenJDK 11 have been removed. In this transition, all components of the Oracle JDK were incorporated into the Oracle OpenJDK as open-source implementations, allowing the Oracle JDK to be replaced with the Oracle OpenJDK. To align with Oracle JDK 11 and Oracle OpenJDK 11, the JDK Flight Recorder and JDK Mission Control were also made available. This also applies to all subsequent Java versions.
JDK Flight Recorder
The tools introduced with JDK 7 in July 2011 for company-wide Java management include diagnostic and monitoring tools for Java runtime environments. JDK Mission Control is an established tool for monitoring, profiling and diagnosing Java applications. The JDK Flight Recorder is comparable to a real flight data recorder. The information stored on it becomes important if something has gone wrong. The same applies to the JDK Flight Recorder: it continuously records information about what happened on the Java Virtual Machine when an error occurs. The tool can be used with any Java applications and application servers, from development to production. The standardized database of the JDK Flight Recorder allows administrators and developers to collaborate on problem-solving and resolve conflicts more efficiently.
JDK Enhancement Proposal (JEP) process provides developer feedback
Through the defined Oracle process of JDK Enhancement Proposals (JEPs), proposed technical improvements are integrated into OpenJDK and the JDK. The JEP structure helps establish a long-term Java feature pipeline and roadmap for JDK release projects and their associated costs.
NullPointerExceptions
The JEP 358 “Helpful NullPointerExceptions” is an example Java SE’s continuous improvement and is a long-awaited feature of JDK 14. It eliminates the need to guess which variable is null when debugging. By analyzing program bytecode, the JVM identifies the exact variable with a null value. It throws a NullPointerException (NPE) at the point where the code attempts to dereference the null reference. By analyzing program bytecode statements, the JVM identifies which variable was null and includes this information in the NullPointerException (NPE) with a detailed message. This data, along with the method, file name, and line number, is provided to the JVM for better debugging.
Records
With the introduction of record types (JEP 359) in 2020, JDK 14 gained a useful preview feature. Developed as part of the Valhalla project, records offer a restricted form of classes, similar to enums. They simplify the creation of data classes by providing built-in data encapsulation, reducing boilerplate code. Records define their representation and enforce it within the associated API, deliberately sacrificing the flexibility of traditional classes, which can decouple API from representation. In return, records provide a significant degree of precision: what belongs together stays together.
Swing as legacy
The status of Java Swing, introduced via the Java Foundation Classes in 1997, is unchanged, meaning it is part of Java SE 8 and will be supported until December 2030, according to the Java SE Support Roadmap. In JDK 24, Swing is included in the java.desktop.jmod module and will continue to be supported.
Learn more about JAX LondonSTAY TUNED!
JavaFX finds its place
Since the presentation of JavaFX 2.0 at JavaOne 2011, the UI technology for Java client applications has maintained a steady developer base. The first notable JavaFX application examples were presented in fall 2012, followed by further business applications built with JavaFX 8. In 2013, previously proprietary JavaFX UI technology became fully open source and was integrated into the OpenJDK project OpenJFX. With the bundling of JavaFX 8 alongside Java SE 8 (JRE/JDK) in March 2014, their versioning was standardized. The JavaFX 8 roadmap highlights the importance of collaboration with the developer community, whose contributions play a key role in the ongoing development of JavaFX/OpenJFX.
With Java modularization, JavaFX 11 was separated from JDK 11 and is now maintained jointly by Oracle JavaFX Engineering and Gluon. JavaFX is added separately to the Oracle JDK, while OpenJFX aligns with OpenJDK. JavaFX 11 (LTS) and later versions are available for download from separate sources. JavaFX 24 (https://jdk.java.net/javafx24/) is offered independently by Oracle and Gluon and can be used as open-source software with Oracle OpenJDK or optionally with Oracle JDK 24 and Java SE Universal Subscription Support. Gluon also provides dedicated support for JavaFX. The JavaFX modules can be integrated using javafx-sdk-24 (SDK) via the Java Module Path or via JavaFX 24 JMODs, which are integrated into your own applications using the jlink tool.
The positive trend of JavaFX UI technology is evident in the increasing downloads from Maven Central from 2019 – as presented at the JFX Days 2019 developer conference in Zurich. Concrete project discussions at the annual JavaFX user meetings in Munich 2018 and online video conferences in 2020, 2021, and 2022 demonstrated the importance of the global JavaFX application landscape. The JFX Adopters Meeting 2024 in Munich (https://www.zeiss.com/meditec/en/news-events/events/jfx-adopters-meeting.html), organized by Carl Zeiss Meditec AG, is considered the world’s only user conference on JavaFX technology, showcasing custom use cases in business-critical areas. JavaFX usage has gradually increased in recent years, with more applications being written with JavaFX again.
JavaFX is a crucial Java UI technology for many small and large companies. Attendees were excited about the new opportunities created by JavaFX’s independence from the JDK, with development now driven by both Oracle and the community. The existing JavaFX developer community outside Oracle is well-established and strong, working alongside Oracle Java Engineering to keep the current JavaFX technology alive. Different JavaFX versions are available for download by the community via Gluon and Oracle. The continuous Oracle Java SE support roadmap, combined with a long-term strategy for JavaFX, gives users with confidence the technology, as there is no long-term technical roadmap for JS and other web technologies.
JavaOne returns
The JavaOne conference, first introduced by Sun Microsystems in 1996, was for discussing all relevant Java topics. Held annually in San Francisco, this global developer conference set the pace for the development of the Java for many years. The enthusiasm of Java developers reached its peak at JavaOne 2001 with 25,000 participants in the Moscone Center. This number was the fire safety limit set by the San Francisco fire chief, and precisely 25,000 participants attended, ensuring there was no need for evacuation!
Oracle Code One replaced the former JavaOne as the successor conference in 2018. Code One focused on various programming languages, technologies, and developer communities. At its debut, the conference emphasized developer code contributions with GitHub, Java, and global collaboration within the Java community through OpenJDK. GitHub presented the OpenJDK project Skara, which implemented an alternative source code management system with code review options for the JDK source code, using Git instead of Mercurial. In the GitHub Skara demo, a JDK 10 feature was added to an older Java program, followed by generating a pull request and analyzing the change. The Git-openjdk-jcheck of the pull request showed that a code reviewer needed to approve the change. The demo illustrated the individual improvements with GitHub in Java development, promoting easier access to Java repositories. In line with JEP 357 (Migration from Mercurial to Git), JEP 369 aims to migrate all OpenJDK projects with a repository to GitHub, including the JDK Feature Releases and JDK Update Releases for version 11 and above. These two JDK improvement proposals were included as components of JDK 16.
With the public OpenJDK repository, it is possible to identify popular developer code patterns early through analysis, allowing for the accurate proposal of desired feature behavior as an OpenJDK JEP for the Java community. Since 2022, the original conference name, JavaOne, has been revived, and JavaOne 2025 will return to California as an independent Java conference.
Conclusion and outlook
The six-month Java release cycle aimed to ensure that new features are reliably provided and that Java feature releases fit together. The time-controlled cycle intends that experimental features receive early feedback from the Java community and are stable before their inclusion in a defined Java LTS release. Features marked as “deprecated” shouldn’t just disappear from the interim releases, but be carefully faded out with the necessary lead time.
According to various surveys taken with developers and companies on the Java LTS versions in productive use, 25% use JDK 8 (LTS), while 25% each use JDK 11 (LTS), JDK 17 (LTS) and JDK 21 (LTS) for their production systems.
The experience made from switching to JDK 8 to JDK 11, JDK 17 and JDK 21 has shown that the “Just run” variant is usable in practice. This means that existing Java applications can be run with the higher Java release without modification thanks to backward compatibility. Nevertheless, even if only in marginal areas, in rare cases possible incompatibility must be considered.
With the “recompile and adapt source code” variant, the old Java code is always kept up to date and supported by common development environments in the best possible way. The Oracle JDK Migration Guide (https://docs.oracle.com/en/java/javase/21/migrate/index.html) offers migration assistance for switching from JDK 8 to JDK 21 (LTS) as well as the intermediate releases and higher Java versions. The future Java feature pipeline is full, as proven by the Amber, Babylon, Leyden, Lilliput, Loom, Valhalla and Panama projects.
Java is one of the most widely used programming languages. With the growing use of AI development services and machine learning, it can be assumed that these technologies will continue to grow together in the future. Java can be used for ML programming, driving the standardization of Java with ML and with the right Java libraries for machine learning, there are no limits for internal and external development teams.
As long as Java best practices are followed and experienced developers implement the coding of business logic efficiently, the programs created can increase the added value for companies. Performance and scalability underline the use in enterprise AI applications, as Java applications can process huge data sets and complex algorithms with minimal performance loss. Regardless of whether Java is used on-premise or in the cloud, it is up to the developers to decide how they want to shape the coming years technologically and where Java is heading.