Beginner

Java SE The Big Picture

Java 17 is used as a reference, but almost all concepts apply to all versions of Java. The goal is not to learn to program in Java, but to understand and appreciate the Java ecosystem as...

Reference version: Java SE 17 (Long-Term Support)

Table of Contents

  1. Course Overview
  2. Introduce the Java platform
  1. Adopt Java
  1. Working with Java
  1. The expanded Java ecosystem

1. Course Overview

This course answers fundamental questions:

  • What is the difference between Java and Java Enterprise?
  • Why adopt Java?
  • What can Java do for me?

Java 17 is used as a reference, but almost all concepts apply to all versions of Java. The goal is not to learn to program in Java, but to understand and appreciate the Java ecosystem as a whole.

This course is aimed at:

  • A developer who wants to evaluate Java as a technology.
  • A Java developer returning after several years away and wanting a refresh.
  • A technical manager who wants to understand what his Java developers are talking about.

The course assumes no prior experience with Java, although general software development experience is helpful.


2. Introduce the Java platform

2.1 Introduction and target audience

Sander Mak identifies three categories of people who take this course:

  1. The non-Java developer: You want to evaluate Java as a technology or simply understand what it is.
  2. The Java Developer Returns: You haven’t developed on the platform in a while and want a refresher on modern Java and its ecosystem.
  3. The technical manager: you are not a developer but want to understand Java to communicate effectively with your teams.

Some code will be presented in this course, but only to illustrate the big picture. It’s never about teaching the code itself.

2.2 Tools used in this course

This course is based on Java SE 17, the Long-Term Support (LTS) version. You are welcome to install Java and try the examples, but this is neither necessary nor expected.

Version policy:

  • Before Java 9: a major version every 3 to 4 years.
  • Since Java 9: ​​two major releases per year.
  • LTS versions (Java 8, Java 11, Java 17…) receive the widest community adoption.

Java distributions: Many vendors package and distribute Java for installation. Everything you learn in this course also applies to any distribution, regardless of vendor:

  • Oracle JDK
  • Eclipse Temurin (Adoptium)
  • Amazon Corretto
  • Microsoft Build of OpenJDK
  • Azul Zulu
  • etc.

2.3 What you will learn

The course consists of four modules:

ModuleTitleDuration
2Introducing the Java Platform17m 5s
3Adopting Java25m 47s
4Working with Java19m 53s
5The Wider Java Ecosystem27m 2s
  • Module 2 — Introducing the Java Platform: the fundamental elements of the Java platform. Spoiler: it’s not just a programming language.
  • Module 3 — Adopting Java: when is Java the right technology? Unique properties, philosophy, comparison with other languages.
  • Module 4 — Working with Java: from desktop applications to the cloud, types of Java applications and language features.
  • Module 5 — The Wider Java Ecosystem: the tools, libraries, frameworks and alternative languages ​​that constitute the true power of Java.

Is Java 2.4 dead?

Java has been around since 1995. Since the turn of the millennium, voices have regularly declared Java dead:

  • Articles in 2002, 2008, 2020, 2021, 2022…

“There are two types of languages: the ones people complain about and the ones nobody uses.”

Java is clearly in the first category — still very widely used. Its areas of application have evolved, but the platform is still alive.

Highlights:

  • Java runs on devices as small as SIM cards and ATM cards, up to the most powerful servers in the cloud.
  • Java literally runs on billions of devices.
  • In 2022, Java appeared in the New York Times crossword: “programming language named for a drink named for an island”.

Java ≠ JavaScript: Despite the similarity in names, there is absolutely no relationship between Java and JavaScript — neither technical nor commercial. The name “JavaScript” was simply used by Netscape in the 90s to take advantage of the popularity of Java at that time.

2.5 The Java platform in three parts

The Java platform is made up of three parts:

┌─────────────────────────────────────────┐
│         Application Bytecode            │
├─────────────────────────────────────────┤
│     Java Standard Edition APIs          │
│        (Bibliothèque standard)          │
├─────────────────────────────────────────┤
│     Java Virtual Machine (JVM)          │
│       (Environnement d'exécution)       │
└─────────────────────────────────────────┘
         Hardware / OS (natif)
  1. The Java programming language: governs the form of source code — what keywords to use, what rules to follow when writing code.

  2. The execution environment (JVM — Java Virtual Machine): where the Java code executes. It abstracts the underlying operating system and processor architecture.

  3. The standard library (Java Standard Edition APIs): contains commonly used features that you can reuse in your applications — collections framework, date and time management, HTTP client, and much more. This is what SE means in Java SE: Standard Edition.

When people talk about Java, they can talk about any of these parts individually or the combination of all three. This ambiguity is common.

The JDK — Java Development Kit: The three parts are grouped into what is called the JDK. You cannot develop Java applications without a JDK. It contains all the tools needed to create and run Java applications:

  • javac — the Java compiler
  • java — the command to launch the JVM
  • javadoc, jshell, jlink, etc.

Java application creation flow:

Code source Java (.java)
        ↓  [javac — Compilateur Java]
    Bytecode (.class)
        ↓  [JVM — Java Virtual Machine]
   Instructions machine natives
        ↓
  Exécution sur le hardware

Bytecode is a mid-level representation, CPU and operating system agnostic. Applications can also use third-party libraries, which are also distributed in bytecode form.

2.6 Compile and run Java code

Here is a concrete example of a simple Java application, the classic Hello World:

Hello.java file:

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello Pluralsight!");
    }
}

Explanations:

  • Any Java source file must end with the .java extension.
  • Inside, we declare a class (Hello). The class groups the code in its braces and gives it a name so that it can be referred to from other codes.
  • The class contains a method (main). A method groups together instructions that can be executed.
  • System.out.println("Hello Pluralsight!") is an statement that prints text to the console. System is a class in the Java SE standard library.

Compile and run steps:

# Étape 1 : Compiler le source en bytecode
javac Hello.java
# Crée le fichier Hello.class contenant le bytecode

# Étape 2 : Exécuter le bytecode avec la JVM
java Hello
# Sortie : Hello Pluralsight!

The Hello.class file contains the bytecode — a low-level but still CPU- and OS-agnostic representation that can be more easily executed by the Java runtime.

2.7 Module 2 Summary

Key points:

  • The Java platform is made up of three parts: the Java programming language, the standard library (Java SE APIs) and the runtime environment (JVM).
  • The JDK (Java Development Kit) brings together these three parts plus the associated tools.
  • The flow is: Java source code → compilation with javac → bytecode → execution on the JVM.
  • The JVM translates the bytecode into native machine instructions for the underlying hardware.

3. Adopt Java

This module answers the question: when and why to adopt Java?

3.1 Java philosophy: readability

There are an estimated 10 million Java developers worldwide, using the platform to build applications and services in almost every industry imaginable.

Java was created primarily as a language for getting work done. It is an industrial language, with no underlying academic motivations. Its goal is not to be at the cutting edge of programming languages, but to be practical and efficient for development teams.

Fundamental principle: Optimize for readability.

This principle is based on the observation that you read existing code much more often than you write it. Software development is a fundamentally collaborative effort. You spend a lot of time reading and understanding other people’s code.

Java tries to provide a clear way to express its intentions. Understandable code is encouraged over “intelligent” code:

“You may understand your ingenious hack today, but will you understand it tomorrow? In a month? In a year? Or will your colleague understand it?”

This is particularly crucial in large-scale collaborative development.

3.2 Java philosophy: stability

Java is conservative in adding new features. When a language has too many different ways to achieve the same result, its learning curve increases dramatically.

Guiding principles:

  • First, do no harm: It is much more difficult to remove a poorly designed feature than to introduce a new one.
  • All new features should empower developers without conflicting with existing features.
  • New features should make Java developers more productive while maintaining the simplicity of the language.

Java 12 — Preview Features: Language features are first introduced behind an experimental flag. Real-world feedback can thus be collected to refine features before finalizing them.

*Backward Compatibility:

This is one of the most important principles of Java. Imagine the massive time wasted by 10 million developers when Java breaks backwards compatibility.

  • Code written for earlier versions of Java will compile and run on newer versions unchanged.
  • Code already compiled to bytecode and distributed (e.g. as a library) will also work on later versions.
  • This allows the huge ecosystem of Java libraries to thrive.
  • A rare compatibility break occurs with relatively long and predictable deprecation cycles.

Java is stable, but constantly modernizing. Coupled with the preview features mechanism and frequent Java releases, it works surprisingly well.

3.3 Java philosophy: openness and community

Oracle owns the Java brand and is the main engine behind the platform, but Java itself is an open technology, and this manifests itself in several ways.

1. Formal specifications:

Java is rigorously specified, unlike some other languages:

  • The Java Virtual Machine Specification: how a JVM should execute bytecode.
  • The Java Language Specification: What valid Java source code looks like and how it should be compiled.

These specifications are managed via the Java Community Process (JCP). JCP members are relevant vendors in the Java world and other leaders in the Java community, who together lead the future of the platform.

2. OpenJDK — Open source reference implementation:

Because Java is formally specified, there may be more than one implementation of the Java platform outside of Oracle’s efforts. For example:

  • IBM has its own JDK implementation.
  • Amazon, Microsoft, Azul, Red Hat, and other vendors offer their own Java distributions.

As of 2020, all JDK development has been moved to GitHub. You can look at the repositories and see exactly what’s going on. The OpenJDK project also hosts many experimental subprojects explored on the openjdk.net site. There are also Java Enhancement Proposals (JEPs), which provide insight into the direction of the platform.

3. The Java developer community:

  • More than 10 million Java developers worldwide: a massive talent pool for any organization.
  • Hundreds of Java User Groups around the world, organizing events where developers meet, exchange experiences and develop their skills.

3.4 Java language

Familiar syntax (C family): Java’s basic syntax and constructs are close to C and other C-family languages:

  • The different scopes are delimited by braces {}.
  • Familiar forms of if-then-else, for loops, switch statements.

Object-oriented programming: Java introduced a great innovation compared to more procedural languages like C: object-oriented. By introducing classes as a way to combine data (fields) and behavior (methods), a new paradigm for modeling code emerged. Classes can inherit from each other for increased modeling flexibility.

Scalable development model: Java offers a very scalable development model, suitable for large codebases:

Classe (class)
    └── regroupe les données (fields) et comportements (methods)
Package
    └── regroupe les classes connexes
Module
    └── regroupe les packages connexes (ajout récent depuis Java 9)

Each level of abstraction allows internal details to be encapsulated and fine-grained access control between elements to be applied.

Static Typing:*

Java is a statically typing language: you must be explicit about the types of the variables you create. The compiler can detect type errors at compile time.

Example compilation error:

// Erreur : incompatibilité de types
public class Hello {
    public static void main(String[] args) {
        int message = "Hello Pluralsight!"; // String cannot be converted to int
        System.out.println(message);
    }
}

Error generated by the compiler:

error: incompatible types: String cannot be converted to int

In languages ​​without static types, such an error would only be detected at runtime — which is problematic because a user will see an unexpected error at runtime. Types help detect bugs early, when they are reported by the compiler.

3.5 The Java runtime: portability

The JVM provides three main advantages:

  1. Portability
  2. Managed runtime (garbage collection, multithreading)
  3. Runtime performance

The WORA principle — Write Once, Run Anywhere:

Write your application once in Java, and the Java platform takes care of running it on Linux, Windows or other platforms, including different CPU architectures.

Why is this important? Apple has changed CPU architecture several times: PowerPC → Intel → ARM. Having to recompile or, worse, rewrite your application every time you want to target a different platform would be terrible.

Operation:

Application Bytecode
        │
        ▼
┌───────────────────┐  ┌───────────────────┐
│   JVM Linux x64   │  │  JVM Windows x86  │
└───────────────────┘  └───────────────────┘
        │                       │
        ▼                       ▼
  Hardware Linux          Hardware Windows

The same bytecode compiled once can run on different JVMs (Linux, Windows, ARM, etc.) without modification. JVMs take care of the translation to native machine instructions.

Limitation: If you need to write code that integrates deeply with the operating system (device drivers, strict real-time applications), the advantages of the JVM turn into disadvantages. Unmanaged languages ​​are better suited in these cases.

Over the past 20 years, JVMs have emerged for everything from mainframes to embedded ARM devices. Java has truly proven that it is possible to write once and run everywhere.

3.6 The Java runtime: a managed runtime

The JVM is sometimes called a managed runtime and Java a managed language because the JVM handles many concerns for you.

1. Automatic Memory Management (Automatic Memory Management):

In low-level languages, you must indicate where and when to allocate memory for objects created in your code, and especially when to free this region of memory. In Java, the JVM manages memory allocation transparently. You don’t have to worry about the location of objects in memory.

2. Garbage Collection:

The garbage collector periodically checks the allocated memory and determines which objects are still in use and which are no longer in use. Memory belonging to unused objects is freed for reuse. Java developers only have to think about business logic, not memory management.

3. Multithreading:

Modern CPUs have many cores available. By creating threads from your Java code, you can easily use the resources of multiple cores in parallel. The JVM supports scheduling code running on different threads to all CPU cores. Combined with the concurrency APIs offered in the Java standard library, this makes it easier to write high-performance multi-threaded code.

4. Just-In-Time (JIT) compilation:

Although the JVM introduces a layer between code and machine instructions, this configuration allows JIT compilation:

  • The JVM analyzes bytecode execution at runtime.
  • It can decide to compile just-in-time into machine instructions very specific to the current CPU, unlocking maximum performance.

Comparison with unmanaged languages:

CriterionJava (managed)C/C++ (unmanaged)
Memory managementAutomatic (GC)Manual
PortabilityJVM by platformRecompilation required
CompilationBytecode + JIT at runtimeDirect machine code (upfront)
CPU optimizationsCPU-specific in runtimeGeneric (less optimized)
Risk of errorsLess (no segfaults)Higher

“When web companies grow up, they turn into Java shops.” — James Governor A notable example: Twitter was infamous for its outages. After migrating from Ruby to Java and the JVM, this problem has largely disappeared.

3.7 Comparison with other languages

Java vs C# (.NET):

C# on the .NET platform is the closest sibling of the Java platform.

CriterionJavaC#/.NET
RuntimeJVMCLR (Common Language Runtime)
BytecodeJava bytecodeIntermediate Language (IL)
Evolution of languageSlow, conservativeFaster, more features
Cross-platformYes, from the beginning.NET Core yes, but fewer targets than the JVM
Open sourceOpenJDK.NET Core (open source)
EcosystemBigger and more diverseStrongly associated with Microsoft
Backward compatibilityVery strictMore liberal historically

If your company is already heavily invested in the Microsoft ecosystem, choosing C# and .NET may make sense. Otherwise, Java provides access to the world’s largest open source library ecosystem.

Java vs C / C++:

C and C++ are low-level languages ​​used for systems programming.

CriterionJavaC/C++
TypeManagedUnmanaged
Memory managementAutomaticManual
RiskFewer memory bugsSegfaults, possible corruptions
PortabilityVery easy (JVM)More difficult
Typical usageEnterprise, web, cloud applicationsDrivers, embedded systems, real-time
CompilationBytecode → JITMachine native code directly

C and C++ are an excellent choice for system-level development (drivers, strict real-time systems), but generally less suitable for developing large-scale enterprise applications or web services.

Java vs JavaScript:

Reminder: Java and JavaScript are two completely different things.

CriterionJavaJavaScript (+ Node.js)
TypingStaticDynamic (TypeScript = optional)
CompilationCompiled to bytecodeInterpreted (JIT in V8)
MultithreadingNative, multiple threadsSingle-threaded (event loop)
PortabilityJVMNode.js on server, client browser
Memory managementAutomatic GCAutomatic GC (V8)
Error detectionAt compile time (types)Especially in execution

TypeScript (which adds optional typing to JavaScript) has gained popularity in part because preventing errors early offsets the inconvenience of having to specify types.

Single-threaded execution of JavaScript can be compensated for with Workers, but the use of multi-core hardware is not as seamless as with Java’s threading capabilities.

There is no “best” language or platform. You decide what best suits your needs and context.

3.8 Module 3 Summary

This module covered many perspectives that play a role in the potential adoption of Java:

  • Philosophy: readability and stability are fundamental drivers. The goal of Java is not to write the shortest code possible, but to write clear and maintainable code.
  • Openness: Java is open, both in the sense of an active community and in the sense of OpenJDK as an open source reference implementation.
  • Object oriented with familiar syntax.
  • Managed Runtime: Java allows developers to write high-level code while achieving excellent performance from the JVM, in a way that is portable across platforms.
  • Java fits into a rich technology landscape with distinct advantages and disadvantages compared to C#, C/C++ and JavaScript.

4. Working with Java

This module explores how Java is used in practice: what types of applications people build with Java.

4.1 Java Desktop

Desktop applications are no longer as popular as they once were, with web applications becoming the norm. However, there are still valid reasons to create desktop applications:

  • Offline use case.
  • User interface complex enough to build in a browser.
  • Interaction with hardware.

Swing:

Java comes with a complete GUI toolkit called Swing. It offers fully Java-based UI controls that do not rely on the operating system for rendering native UI controls. This means that Swing apps render and look the same on different platforms.

  • Several looks and feels are available — some imitate the look of a particular OS, others aim for a uniform cross-platform look.
  • Notable example: IntelliJ IDEA, the very popular Java IDE, is itself built with Swing.

JavaFX:

Later in Java’s history, a new GUI toolkit called JavaFX was developed.

  • You can create code-driven UIs via JavaFX APIs.
  • There is also a declarative XML-based format for UIs called FXML, allowing the design of the UI to be decoupled from the underlying application code.
  • Much more advanced UI components than Swing.
  • Support for hardware accelerated animations, effects and 3D graphics.
  • Stylization via CSS (like for the web).

Examples of JavaFX at NASA:

  • Deep Space Trajectory Design application.
  • Ground Flight Dynamics System supporting James Webb Space Telescope operations.

Development:

  • Until Java 10: JavaFX was included in the JDK.
  • From Java 11: JavaFX is separated from the JDK and developed in its own project called OpenJFX (subproject of OpenJDK).

If you want to create a Java desktop application with just a standard JDK, Swing is your best choice. For a modern desktop application with all the advanced capabilities, OpenJFX is worth considering.

Desktop application development has become a relatively small niche. Mainstream Java development is geared more towards server-side applications.

4.2 Java Enterprise

Java plays a major role in the development of enterprise applications which generally have high complexity:

  • Web front-ends
  • Transactional databases
  • Integration with many external systems
  • Scheduled Tasks
  • etc.

This goes well beyond what the Java SE APIs offer.

The problem of multiple dependencies:

Without a structured solution, you could end up with dozens or even hundreds of external libraries. The disadvantages:

  • Library selection (expensive in time and effort).
  • Making libraries work together (hard).
  • Update management and ongoing compatibility.

Java EE (Java Enterprise Edition):

Java EE appeared as a solution to this problem. It offers an integrated set of technologies to efficiently develop enterprise applications. Launched in 1999, Java EE offers APIs for:

  • Interact with databases (JPAJava Persistence Architecture)
  • Building web front ends (JSFJakarta Server Faces)
  • Apply a uniform application security model
  • Support asynchronous messaging via message brokers
  • Manage XML and JSON (JSON-B, JAXB)
  • Write services with transactional business logic (EJBEnterprise JavaBeans)

Application Servers:

Java EE is just a specification. You need an implementation to run the applications:

Application serverSupplierType
Oracle WebLogicOracleCommercial
Red Hat WildFlyRed HatOpen Source
IBM WebSphereIBMCommercial
Apache TomEEApacheOpen Source
GlassFishEclipse/OracleOpen Source
PayaraPayaraOpen/Commercial

Transition to Jakarta EE:

Oracle has decided to no longer develop Java EE specifications after Java EE 8 in 2017. The Eclipse Foundation has taken over, developing Java EE technologies into an open source project under a new name: Jakarta EE. Since the takeover, several versions of Jakarta EE have been published (site: jakarta.ee).

4.3 Java in the Cloud

The traditional model:

Data Center
├── Machine dédiée #1 ─► Application Server (WebLogic, WildFly)
│                              └── App Java EE (monolithique)
├── Machine dédiée #2 ─► Application Server
└── Machine dédiée #3 ─► Application Server (cluster)

Traditional Java EE applications are large and complex in their monolithic structure.

The Cloud-Native model:

Cloud-native development (elastic cloud computing: AWS, Azure, Google Cloud) is fundamentally different:

Cloud Élastique
├── Microservice A (Docker container) ─► Scale x3
├── Microservice B (Docker container) ─► Scale x1
├── Microservice C (Docker container) ─► Scale x5
└── API Gateway / Service Mesh

New cloud-native concerns:

  • Security in elastically scaling environments.
  • Services are dynamically discovered to communicate.
  • Fast deployments with Docker containers.
  • Monitoring and tracing distributed between services.

Microframeworks:

New approaches have emerged in the Java ecosystem for building cloud-native services. These frameworks are often called microframeworks (micro referring both to microservices and to the fact that these frameworks are much lighter than traditional Java EE application servers):

FrameworkDescription
Spring BootThe most popular Java microframework. Built on Spring Framework + selected libraries for cloud issues. Runs directly on Java SE, without an application server.
MicroProfileBorn from Java EE. Selects a subset of enterprise Java specifications relevant to cloud-native. Allows you to reuse Java EE knowledge.
Vert.xResponsive, open source framework (Red Hat).
QuarkusFramework optimized for the cloud, designed for containers, open source (Red Hat).

Spring Boot is arguably the most popular Java microframework. A Spring Boot service is ultimately bundled into a single Java application that runs on Java SE — no more big Java EE application server involved.

4.4 Language features

Java is an object-oriented language. Concepts like classes, objects, and interfaces have been around since the early days of Java. But over the last decade or so, features inspired by functional programming have been added.

Lambdas (Java 8)

With a lambda expression, you can define a function without having to declare a surrounding class.

// Déclaration d'une lambda
Function<Integer, Integer> increment = value -> value + 1;

// La lambda n'est pas encore appelée ici.
// Elle peut être passée à d'autres méthodes ou composée avec d'autres fonctions.

Streams API (Java 8)

Instead of imperatively iterating over collections with for loops, the Streams API allows elements in collections to be processed in a more functional way.

Example using JShell (the Java interactive environment, introduced in Java 9):

jshell> var result = List.of(1, 2, 3, 4)
   ...>     .stream()
   ...>     .filter(n -> n > 2)        // Garde seulement 3 et 4
   ...>     .map(increment)            // Applique la lambda increment (3→4, 4→5)
   ...>     .toList();
result ==> [4, 5]

Steps:

  1. List.of(1, 2, 3, 4) — creates a list of 4 integers.
  2. .stream() — transforms the collection into a stream, unlocking the Streams API.
  3. .filter(n -> n > 2) — only keeps elements > 2 (3 and 4).
  4. .map(increment) — transforms each remaining element with the increment function (3→4, 4→5).
  5. .toList() — materializes the stream into a new collection.

Together, lambdas and streams have profoundly changed the way people write Java code since Java 8.

Type Inference with var (Java 10)

Java is a statically typed language — all types must be known and checked at compile time.

// Avant Java 10 : déclarations de types explicites (redondance)
String message = "Hello";
List<String> names = new ArrayList<>();
Map<String, Integer> scores = new HashMap<>();

// Java 10+ : inférence de type avec var
var message = "Hello";         // String inféré
var names = new ArrayList<String>(); // ArrayList<String> inféré
var scores = new HashMap<String, Integer>(); // HashMap<String, Integer> inféré

With var, the Java compiler infers the actual type of the variable based on the type of the expression on the right. Each variable always has a type, but we let the compiler infer it for us. In many cases, var makes the code both shorter and clearer.

Records (Java 16)

Records are a special type of class to use when all you care about is the data the class should contain. They provide an efficient way to model immutable data classes.

Before records — lots of boilerplate code:

// Classe Product "classique" avec tous ses boilerplates nécessaires
public final class Product {
    private final String name;
    private final String vendor;
    private final double price;
    private final boolean inStock;

    public Product(String name, String vendor, double price, boolean inStock) {
        this.name = name;
        this.vendor = vendor;
        this.price = price;
        this.inStock = inStock;
    }

    public String name()    { return name; }
    public String vendor()  { return vendor; }
    public double price()   { return price; }
    public boolean inStock(){ return inStock; }

    // + equals(), hashCode(), toString() à implémenter...
}

With records (Java 16+):

// Une seule ligne remplace tout le code ci-dessus !
record Product(String name, String vendor, double price, boolean inStock) {}

// Utilisation dans JShell :
jshell> var p = new Product("Widget", "ACME", 9.99, true);
p ==> Product[name=Widget, vendor=ACME, price=9.99, inStock=true]

By default, record formatting displays all fields with their initialized values ​​clearly.

Records provide Java developers with a much more concise way to model core objects in Java applications.

Other notable features

Although not detailed in this course, Java has continued to evolve including:

  • Sealed classes (Java 17): Classes and interfaces that limit which other classes or interfaces can extend or implement them.
  • Pattern matching for instanceof (Java 16).
  • Switch expressions (Java 14).

4.5 Summary of Module 4

  • Desktop Java: Swing (standard, cross-platform) and JavaFX/OpenJFX (modern, animations, CSS) for desktop applications.
  • Enterprise Java: Java EE (now Jakarta EE) — its original approach based on monolithic application servers is still used, but the industry has changed dramatically with the rise of the cloud.
  • Cloud-Native: development of microservices for the cloud, mainly via microframeworks like Spring Boot, which offer a much lighter development model.
  • Language features: lambdas and streams (functional programming), var (type inference), records (concise data classes) — Java maintains its focus on improving developer productivity while remaining true to the platform’s philosophy.

5. The expanded Java ecosystem

The real power of the Java platform is not Java itself, but all the tools, libraries and frameworks that surround it.

5.1 Spring Framework

Spring Framework has single-handedly changed the way enterprise Java development is done.

History:

  • Around 2002, Spring Framework emerged as an alternative to traditional Java EE development.
  • At the time, the Java EE programming model was considered cumbersome, and Java EE itself a slow-moving technology due to its extensive specification process.
  • Spring arrived as an alternative, supposedly lighter approach.
  • Since then, Spring has gained popularity and is widely used.

Dependency Injection (DI) — the core of Spring:

Spring is basically a dependency injection container. DI is a form of inversion of control (IoC), also called the Hollywood principle: “Don’t call us, we’ll call you”.

Problem without DI:

// Sans injection de dépendances :
public class LoginService {
    // LoginService instancie directement ses dépendances
    private UserService userService = new UserService();       // Couplage fort
    private AccountService accountService = new AccountService(); // Difficile à tester

    public boolean login(String username, String password) {
        // utilise userService et accountService directement
    }
}

Disadvantages:

  • Strong coupling: LoginService depends on the exact implementation classes.
  • Difficult to test: no way to replace dependencies with mocks.

Solution with Spring DI:

// Avec Spring et injection de dépendances :
@Service
public class LoginService {
    private final UserService userService;
    private final AccountService accountService;

    // Spring injecte les dépendances via le constructeur
    public LoginService(UserService userService, AccountService accountService) {
        this.userService = userService;
        this.accountService = accountService;
    }

    public boolean login(String username, String password) {
        // utilise les interfaces injectées
    }
}
  • Spring takes responsibility for instantiating all classes and providing dependencies to LoginService.
  • This decouples LoginService from other classes, especially if you introduce Java interfaces between the concrete implementations and their usage.
  • When testing, you can provide alternative implementations or mocks of dependencies.

Spring configuration:

Instructions can be provided:

  • Via annotations on your code (@Service, @Component, @Autowired, etc.).
  • Via explicit configuration code (@Configuration, @Bean).
  • Via external XML configuration (possible but not recommended these days).

Spring Framework has evolved to become much more than a DI container:

Spring componentDescription
Spring CoreBasic DI/IoC Container
Spring Web MVCClassic MVC web framework
Spring WebFluxResponsive and Modern Alternative to Spring MVC
Spring BootMicroframework for cloud-native microservices
Spring DataData access abstraction (JPA, MongoDB, Redis, etc.)
Spring SecurityApplicator security (authentication, authorization)
Spring CloudTools for distributed microservices architectures
Spring BatchFramework for batch processing

Spring Framework delivered on its promise and surpassed Java Enterprise in popularity. Chances are you’ll encounter Spring while working with Java.

Minimum Spring Boot example:

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "Hello from Spring Boot!";
    }
}

The Java ecosystem offers libraries for virtually any task. Here is an overview of the most important ones:

Tests — JUnit

JUnit is the most popular library for testing code in isolation (unit tests). Simply annotate a method with @Test.

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class CalculatorTest {
    @Test
    void testAddition() {
        Calculator calc = new Calculator();
        int result = calc.add(1, 2);
        assertEquals(3, result);
    }
}

JUnit supports running all tests and producing reports, whether in an IDE or in an automatic build script. Unit testing is adopted by virtually every Java development team.

Tests — Mockito

Mockito allows real dependencies of a class to be substituted with mocks (fake controlled objects) during tests.

// Si LoginService dépend de UserService, Mockito permet de "mocker" UserService
UserService mockUserService = Mockito.mock(UserService.class);
Mockito.when(mockUserService.findUser("john")).thenReturn(new User("john"));

LoginService loginService = new LoginService(mockUserService, ...);
// Tester loginService sans vraie base de données

The developer has full control over all interactions between the code under test and its dependencies.

Persistence — Hibernate

Hibernate is a widely used library for data persistence. It allows you to map Java objects to tables in a relational database.

  • ORM (Object-Relational Mapping): Hibernate translates between the Java object world and the SQL relational world.
  • Built on the Java Database Connectivity API (JDBC), part of Java SE, but provides a higher level abstraction.
  • Save and retrieve Java objects from a relational database with minimal boilerplate.
  • Implements the JPA (Java Persistence API) specification, now part of Jakarta EE.
@Entity
@Table(name = "products")
public class Product {
    @Id
    @GeneratedValue
    private Long id;

    private String name;
    private double price;

    // Hibernate génère les requêtes SQL nécessaires
}

JSON — Jackson / Gson / JSON-B

When developing microservices, it is inevitable to handle JSON serialization and deserialization.

LibraryDescription
JacksonCommon choice, high performance
GsonDeveloped and open source by Google
JSON-BJSON Binding, part of Jakarta EE
// Exemple avec Jackson
ObjectMapper mapper = new ObjectMapper();

// Sérialisation : Java → JSON
Product product = new Product("Widget", 9.99);
String json = mapper.writeValueAsString(product);
// {"name":"Widget","price":9.99}

// Désérialisation : JSON → Java
Product p = mapper.readValue(json, Product.class);

Apache Commons Libraries

Apache is an open source foundation that hosts many Java libraries. Commons libraries help with everyday coding tasks:

  • Commons CLI — create Java applications from the command line.
  • Commons IO — various input/output tasks.
  • Commons CSV — work with CSV files.
  • And many more at commons.apache.org.

Apache also offers a widely used HTTP client, although starting with Java 11, Java now includes a modern HTTP client API, reducing the need for external libraries for HTTP calls.

Logging — SLF4J, Log4j, Logback

Every serious Java application needs logging for monitoring and troubleshooting in production.

LibraryRole
Log4jPopular logging library (notorious for security incident in 2022)
LogbackAlternative to Log4j, very efficient
Commons LoggingApache Logging Library
SLF4JSimple Logging Facade for Java — unified facade for easy implementation switching
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyService {
    private static final Logger logger = LoggerFactory.getLogger(MyService.class);

    public void processOrder(Order order) {
        logger.info("Processing order: {}", order.getId());
        // ...
    }
}

SLF4J allows coding against a unified API and swapping logging implementations underneath if desired. This is similar to the notion of the Jakarta EE specification with various implementations.

Other notable libraries

LibraryUsage
Project Reactor / AkkaResponsive Programming
NettyHigh performance network applications
CaffeineMemory efficient cache strategy
Hazelcast / EhcacheDistributed cache
Apache KafkaDistributed messaging, event streaming

When you use Java, there is always a library that has you covered for what you need to accomplish.

5.3 Development tools

IDEs (Integrated Development Environments)

Although Java source code is plain text, writing Java code in an IDE rather than a text editor is much more productive:

  • Syntactic highlighting — clearly distinguishes the different elements of the source code.
  • Code navigation — quickly navigate between related parts of your code, including relevant documentation.
  • Real-time error detection — reports compilation errors and type errors without having to invoke the compiler manually.
  • Intelligent auto-completion — provides context-based completions.
  • Automatic refactoring — rewrites code structurally differently while preserving semantics.
  • Integrated compilation and execution — compiles and launches your application directly from the IDE.
  • Debugging — debug the code during execution, set breakpoints and inspect the current state of variables.

The two most used Java IDEs:

IDEEditorLicenseNote
IntelliJ IDEAJetBrainsCommunity Edition (free/open source) + Ultimate (commercial)Recommended
EclipseEclipse FoundationFully open sourceVery widespread

The most important thing is to master the features of your IDE, preferably with keyboard shortcuts, because it’s a huge productivity boost.

Build Tools

Compiling with javac and running with java works for simple examples, but to develop a real Java application, build tools are essential.

Objectives of the build tools:

  • Describe the steps necessary to build and package a complete application.
  • Allow reproducible builds (same result on different machines).
  • Compile Java code, run tests, package for deployment.
  • Manage the modularity of the application (submodules, dependencies between modules).
  • Download external dependencies (third party libraries).

Maven:

Maven is the most used build tool in Java. Builds are described in an XML file called pom.xml (Project Object Model) — declarative in nature.

<!-- pom.xml — exemple de dépendance Spring Boot -->
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>my-app</artifactId>
    <version>1.0.0</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.9.3</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

Maven standard directory structure:

my-app/
├── pom.xml
└── src/
    ├── main/
    │   └── java/
    │       └── com/example/
    │           └── MyApp.java
    └── test/
        └── java/
            └── com/example/
                └── MyAppTest.java

Maven makes many assumptions about defaults in the codebase, which makes most Maven builds look the same and easy to get started with.

Gradle:

Gradle is the second most popular Java build tool. The biggest difference with Maven is that builds are not specified in declarative XML, but using the Groovy scripting language (or Kotlin DSL).

// build.gradle — exemple avec Groovy DSL
plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.0'
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.junit.jupiter:junit-jupiter:5.9.3'
}

repositories {
    mavenCentral()
}
CriterionMavenGradle
FormatDeclarative XMLGroovy/Kotlin DSL (scriptable)
FlexibilityMore rigid, uniformMore flexible, but potentially more complex
Incremental buildsNo (standard)Yes (only modified code triggers steps)
Learning curveSofterMore pronounced
UniformityVery uniform between projectsVaries depending on the projects

Maven Central:

There is a huge public Java library repository called Maven Central, used by Maven and Gradle to download any library needed to build an application.

  • You only need to specify the coordinates (groupId, artifactId, version).
  • Maven or Gradle downloads the correct artifacts.
  • The transitive dependencies of each specified dependency are also retrieved automatically.

With a Java and Maven Central build tool, you never have to manually locate and download external dependencies again.

5.4 Alternative languages ​​on the JVM

The Java ecosystem includes many languages ​​other than Java. For what ?

Code Source Kotlin/Scala/Groovy
        ↓  [Compilateur du langage]
    Bytecode Java (.class)
        ↓  [JVM]
   Exécution native

Any language can compile to Java bytecode and run on the JVM. These languages can thus:

  • Focus on designing a different language.
  • Leverage the JVM’s existing managed execution environment.
  • Be interoperable with existing Java libraries (also distributed in bytecode).
  • Access the entire huge ecosystem of Java libraries.

Reasons to choose alternative JVM languages:

  1. Developer productivity: a new language is not weighed down by the compromises of backward compatibility.
  2. Conciseness: some prefer more concise language.
  3. Different paradigms: functional programming, dynamic typing, etc.

Scala

Scala merges object-oriented programming with functional programming.

// Scala — exemple de fonctionnel
val numbers = List(1, 2, 3, 4)
val result = numbers
  .filter(_ > 2)
  .map(_ + 1)
// result: List[Int] = List(4, 5)

// Case class (équivalent des records Java)
case class Product(name: String, vendor: String, price: Double)
val p = Product("Widget", "ACME", 9.99)
CharacteristicScala
ParadigmMulti-paradigm (OO + functional)
TypingStatic, very advanced type system
Java InteroperabilityGood
Learning curveVery high
PerformanceSlow compiler on large codebases

Experienced Scala developers can be very productive, but the learning curve is often perceived as very steep.

Kotlin

Kotlin is a more recent addition to the JVM language collection. Its objective: to rethink the Java language without backward compatibility constraints.

// Kotlin — exemple
val numbers = listOf(1, 2, 3, 4)
val result = numbers.filter { it > 2 }.map { it + 1 }
// result: [4, 5]

// Data class (inspire les records Java)
data class Product(val name: String, val vendor: String, val price: Double)
val p = Product("Widget", "ACME", 9.99)

// Null safety
var name: String? = null // Nullable
var nonNullName: String = "Hello" // Non-nullable, erreur à la compilation si null
CharacteristicKotlin
CreatorJetBrains (creators of IntelliJ)
ParadigmPragmatic, multi-paradigm
TypingStatic with null safety
Java InteroperabilityComplete (more than Scala)
TargetsJVM, Android, iOS, Web (Kotlin Multiplatform)
Learning curveModerate

Highlights:

  • 2017: Google officially endorses Kotlin as the language for Android development.
  • Kotlin Multiplatform: compiles to platforms other than the JVM (iOS, Android, web), allowing code to be shared between the browser and the back-end, or between the mobile app and the back-end.
  • Kotlin’s data classes inspired the addition of records in Java.

Groovy

Groovy is a dynamic scripting language for the JVM, belonging to Apache.

// Groovy — exemple
def numbers = [1, 2, 3, 4]
def result = numbers.findAll { it > 2 }.collect { it + 1 }
// result: [4, 5]

// Syntaxe proche de Java, mais plus concise
class Product {
    String name
    double price
}

def p = new Product(name: "Widget", price: 9.99)
println p.name // Widget
CharacteristicGroovy
ParadigmDynamic Scripting, OO
TypingDynamic (with optional typing via annotation)
Java InteroperabilityExcellent (syntax very close to Java)
CompilationInterpreted at runtime OR compiled to bytecode
Common useBuild scripts (Gradle), tests

Typical use cases:

  • Gradle uses Groovy as the language to configure builds.
  • Introduced into existing codebases on top of Java code to write tests flexibly.

Comparison of alternative JVM languages:

CriterionScalaKotlinGroovy
ParadigmMulti (OO + FP)Multi (pragmatic)Dynamic Scripting
TypingStatic (advanced)Static (null safe)Dynamic (static opt-in)
PopularityHigh but nicheVery high (Android)Moderate
Learning curveVery highModerateLow
Java InteroperabilityGoodExcellentExcellent
TargetsJVMJVM + multiplatformJVM

Many of these alternative JVM languages ​​have inspired changes in the Java language itself. It’s actually a good thing for the Java platform as a whole to have these alternatives to keep moving forward.

5.5 Conclusion and next steps

Summary of the 4 modules:

  1. Introducing the Java Platform: Java is alive and cross-platform. It compiles into bytecode which runs on the JVM. The platform = language + standard library + JVM.
  2. Adopting Java: Philosophy of readability and stability. Portable and efficient managed runtime. Comparisons with C#, C/C++, JavaScript.
  3. Working with Java: Desktop (Swing, JavaFX), enterprise (Jakarta EE), cloud-native (Spring Boot, microframeworks). Lambdas, streams, var, records.
  4. The Wider Java Ecosystem: Spring Framework, JUnit/Mockito, Hibernate, logging, tools (IntelliJ, Eclipse, Maven, Gradle, Maven Central), JVM languages ​​(Scala, Kotlin, Groovy).

Resources to go further:

ResourceDescription
Java SE Path (Pluralsight)Complete course to learn Java
Java SE 17 Fundamentals (Pluralsight)Learn basic Java programming skills
Spring Big Picture (Pluralsight)Spring Framework Overview
Jakarta EE Big Picture (Pluralsight)Jakarta EE Overview
What’s New in Java (Pluralsight)Course by Java version (since Java 9)
Working with the Java Module System (Pluralsight)Java 9+ system module by Sander Mak
Java 9 Modularity (O’Reilly)Book by Sander Mak
openjdk.netOpenJDK project, JEPs, subprojects
jakarta.eeJakarta EE Specifications
commons.apache.orgApache Commons Libraries

Follow author:

  • Twitter: @Sander_Mak
  • LinkedIn: Sander Mak
  • Pluralsight author page: follow for new training

6. Appendix: Java Platform Diagram

┌─────────────────────────────────────────────────────────────────┐
│                       APPLICATION                                │
│              (Code source Java — .java files)                    │
└─────────────────────────────┬───────────────────────────────────┘
                              │  javac (Java Compiler)
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                    APPLICATION BYTECODE                          │
│                      (.class files)                              │
│         ┌──────────────────────────────────────────┐            │
│         │  Bibliothèques tierces (bytecode)         │            │
│         │  (Hibernate, Spring, JUnit, etc.)         │            │
│         └──────────────────────────────────────────┘            │
└─────────────────────────────┬───────────────────────────────────┘
                              │
┌─────────────────────────────▼───────────────────────────────────┐
│              JAVA STANDARD EDITION APIs                          │
│    (Collections, I/O, HTTP Client, Date/Time, etc.)             │
└─────────────────────────────┬───────────────────────────────────┘
                              │
┌─────────────────────────────▼───────────────────────────────────┐
│              JAVA VIRTUAL MACHINE (JVM)                          │
│   ┌─────────────────────┐  ┌─────────────────────────────────┐  │
│   │  Garbage Collector  │  │   JIT Compiler                  │  │
│   │  (Memory Mgmt)      │  │   (Bytecode → Machine Code)     │  │
│   └─────────────────────┘  └─────────────────────────────────┘  │
│   ┌─────────────────────────────────────────────────────────┐    │
│   │   Thread Scheduler (Multithreading Management)         │    │
│   └─────────────────────────────────────────────────────────┘    │
└─────────────────────────────┬───────────────────────────────────┘
                              │
┌─────────────────────────────▼───────────────────────────────────┐
│               OS + HARDWARE (natif)                              │
│         Linux / Windows / macOS / ARM / x86 / ...               │
└─────────────────────────────────────────────────────────────────┘


Search Terms

java · se · backend · architecture · full-stack · web · libraries · philosophy · platform · tools · development · features · language · languages · notable · runtime · tests

Interested in this course?

Contact us to book it or get a custom training plan for your team.