Skip to content
Java logo

Java

First appeared 1995 · James Gosling

The enterprise workhorse — thirty years old, still runs a large share of the world's back ends.

Overview

Java is a high-level, class-based, object-oriented programming language designed to have as few implementation dependencies as possible. Developed in the early 1990s by James Gosling and his team at Sun Microsystems, Java has become one of the most widely adopted programming languages globally. It emphasizes portability, scalability, and maintainability, making it a top choice for enterprise applications, Android development, cloud computing, and server-side systems. Java is compiled into bytecode that runs on the Java Virtual Machine (JVM), allowing the same code to run on multiple platforms without modification. Its rich standard library includes tools for data structures, networking, concurrency, and GUI development. Java supports multiple programming paradigms, including object-oriented, functional, and concurrent programming. Its ecosystem is vast, with frameworks such as Spring, Hibernate, and Jakarta EE enabling developers to build robust, scalable, and secure applications. Over decades, Java has influenced numerous modern programming languages and continues to be a core technology in many software development environments, thanks to its reliability, strong typing, and community support.

Key facts

The reference details, without the paragraph.

First appeared
1995
Designed by
James Gosling at Sun Microsystems
Typing
Static, strong and nominal, with type inference for local variables (`var`)
Execution
Compiled to bytecode, run on the JVM with a just-in-time compiler
Memory model
Automatic — generational garbage collection (G1, ZGC, Shenandoah)
Package manager
Maven or Gradle, backed by Maven Central
File extensions
.java, .class, .jar
Current LTS
Java 21 (2023) and Java 25 (2025)
Release cadence
A feature release every six months, an LTS every two years
Licence
OpenJDK is GPLv2 with the Classpath Exception

History

How the language got here — the decisions that still shape how you write it.

Java was created by James Gosling, Mike Sheridan, and Patrick Naughton at Sun Microsystems in 1991 as part of the Green Project, initially intended for interactive television and embedded systems. The project evolved into a general-purpose programming language emphasizing portability and cross-platform compatibility. Released publicly in 1995, Java introduced the revolutionary concept of 'Write Once, Run Anywhere' through the Java Virtual Machine (JVM), allowing programs to execute on any platform with a compatible JVM. Java quickly gained popularity in the enterprise software world, powering web applications, banking systems, and large-scale corporate software. Its evolution over time includes the addition of generics, lambda expressions, streams, modularization, and enhanced memory management, keeping the language modern while retaining backward compatibility. Java’s syntax draws heavily from C and C++, offering familiarity while abstracting low-level complexities. The language emphasizes robustness, security, and maintainability, features critical for large-scale software systems. Java’s extensive ecosystem, including tools, libraries, frameworks, and integrated development environments (IDEs) like IntelliJ IDEA and Eclipse, has cemented its position as a staple in software development. Open-source initiatives, active community engagement, and regular updates ensure Java remains relevant in modern computing contexts, from server-side applications to cloud-native solutions and Android development. The Java community organizes conferences such as JavaOne and maintains extensive documentation and tutorials, making it accessible to learners and professionals alike. Java’s influence extends beyond programming languages; it has shaped software engineering practices, design patterns, and development methodologies. Its combination of portability, scalability, and reliability has made it a cornerstone of the programming world for decades.

  1. 1991

    The Green Project

    James Gosling starts work on a language for interactive television set-top boxes at Sun. It is called Oak, after a tree outside his office. The television market never materialises.

  2. 1995

    Write once, run anywhere

    Java launches aimed at the web, with applets running inside Netscape. The applets are forgotten; the promise of portable bytecode running on any JVM turns out to be the durable idea.

  3. 1998

    Java 2 and the enterprise

    The platform splits into editions and gains Swing and the Collections Framework. Java becomes the default choice for business software.

  4. 2004

    Java 5 modernises the language

    Generics, annotations, enums, autoboxing and the enhanced `for` loop arrive together — arguably the largest single upgrade in Java's history.

  5. 2010

    Oracle acquires Sun

    Stewardship passes to Oracle, triggering years of licensing anxiety that ultimately push the ecosystem toward OpenJDK builds as the norm.

  6. 2014

    Java 8 — lambdas and streams

    Functional-style programming arrives, along with `Optional` and a sane date-time API. Java 8 becomes the most widely deployed version in history and stays that way for a decade.

  7. 2017

    Six-month releases

    Java moves from multi-year mega-releases to a predictable cadence, with long-term-support versions every few years. Features ship when ready instead of holding up a release.

  8. 2021

    Records, sealed types and pattern matching

    Java 17 lands a set of features aimed squarely at boilerplate — data carriers in one line, closed type hierarchies, and `switch` that can destructure.

  9. 2023

    Virtual threads

    Java 21 ships Project Loom's virtual threads: millions of cheap threads that make straightforward blocking code scale like asynchronous code. It removes much of the reason to write reactive pipelines.

What it is good at

The reasons teams pick it, stated concretely.

  • Backwards compatibility measured in decades

    Code compiled in 2005 generally still runs. For organisations with software older than some of their staff, this is not a nice-to-have — it is why Java is there at all.

  • The JVM is exceptional engineering

    Thirty years of JIT compilation, escape analysis and garbage-collector research produce a runtime that is genuinely fast and can be tuned for either throughput or sub-millisecond pause times.

  • Tooling that is decades ahead

    IntelliJ IDEA and Eclipse offer refactoring, debugging and profiling that other ecosystems are still catching up to. Async-profiler, JFR and heap dump analysis make production problems tractable.

  • A deep, boring, reliable ecosystem

    Spring, Hibernate, Kafka, Netty and the Apache stack are mature, documented, and used at scale by thousands of companies. Answers to your problem exist, and they are usually a decade old and still correct.

  • Virtual threads changed the concurrency story

    Since Java 21 you can write simple blocking code and still serve hundreds of thousands of concurrent connections, without the cognitive cost of a reactive framework.

Trade-offs

Every language costs you something. Knowing what, before you commit, is the whole point.

  • Verbosity, though far less than its reputation

    Java still asks for more ceremony than Kotlin or Python. Records, `var` and pattern matching have removed much of it, but the reputation was earned and lingers.

  • Slow startup and a large memory footprint

    JVM warm-up costs hundreds of milliseconds and a baseline heap in the tens of megabytes. This is invisible for a long-running server and painful for CLI tools and scale-to-zero functions. GraalVM native images address it at the cost of build complexity and reflection constraints.

  • Framework-heavy conventions

    A typical Spring application relies on annotations, classpath scanning and dependency injection that make behaviour hard to trace from source alone. Powerful once learned, opaque before then.

  • Version fragmentation

    A large amount of production code is still on Java 8 or 11, so tutorials, Stack Overflow answers and libraries span a wide range of language capability. Check which version an example assumes.

  • Type erasure in generics

    Generic types are erased at compile time, so you cannot write `new T[]` or check `instanceof List<String>`. It preserved compatibility in 2004 and has been an irritation ever since.

Code examples

Not syntax tours — the idioms that make code read like the language rather than a translation of another one.

Records replace the data-class boilerplate
public record Order(String id, String customer, BigDecimal total) {

    // Compact constructor — validation without repeating the fields.
    public Order {
        if (total.signum() < 0) {
            throw new IllegalArgumentException("total must not be negative");
        }
    }

    public boolean isLarge() {
        return total.compareTo(new BigDecimal("1000")) > 0;
    }
}

var order = new Order("A-1", "Ada", new BigDecimal("1500"));
System.out.println(order);          // Order[id=A-1, customer=Ada, total=1500]
System.out.println(order.isLarge()); // true
One line replaces the constructor, getters, `equals`, `hashCode` and `toString` that used to run to eighty lines or need Lombok. Records are immutable by design, which makes them safe to share across threads.
Streams express the transformation, not the loop
record Employee(String name, String department, int salary) {}

Map<String, Integer> payrollByDepartment = employees.stream()
    .filter(e -> e.salary() > 50_000)
    .collect(Collectors.groupingBy(
        Employee::department,
        Collectors.summingInt(Employee::salary)
    ));

Optional<Employee> topEarner = employees.stream()
    .max(Comparator.comparingInt(Employee::salary));

topEarner.ifPresent(e -> System.out.println(e.name()));
`Optional` forces you to acknowledge that an empty list has no maximum, which is exactly the case that used to produce a `NullPointerException`. Add `.parallelStream()` and the same pipeline uses every core — worthwhile only for large collections and genuinely independent work.
Pattern matching and sealed hierarchies
sealed interface Shape permits Circle, Rectangle, Triangle {}

record Circle(double radius) implements Shape {}
record Rectangle(double width, double height) implements Shape {}
record Triangle(double base, double height) implements Shape {}

static double area(Shape shape) {
    return switch (shape) {
        case Circle c        -> Math.PI * c.radius() * c.radius();
        case Rectangle r     -> r.width() * r.height();
        case Triangle t      -> t.base() * t.height() / 2;
    };
}
`sealed` tells the compiler the complete list of implementations, so the `switch` needs no `default` — and adding a fourth shape turns every unhandled `switch` into a compile error rather than a runtime surprise.
Virtual threads: blocking code that scales
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    List<Future<String>> results = urls.stream()
        .map(url -> executor.submit(() -> fetch(url)))   // blocking call, cheap thread
        .toList();

    for (var future : results) {
        System.out.println(future.get());
    }
}  // close() waits for every task to finish
Each task gets its own virtual thread, which costs a few hundred bytes rather than a megabyte of stack. Ten thousand concurrent blocking requests are now reasonable — the pattern that previously required a reactive framework to survive.

Common pitfalls

The mistakes that cost everyone an afternoon at least once.

  • Comparing strings with `==`

    `==` compares references. String literals are interned so it sometimes appears to work, then fails on a string built at runtime. Always use `.equals()`, or `Objects.equals()` when either side may be null.

  • Overriding `equals` without `hashCode`

    Objects that are equal but hash differently silently disappear inside a `HashMap` or `HashSet`. Override both, or use a record and get both for free.

  • Mutating a collection while iterating it

    Removing inside an enhanced `for` loop throws `ConcurrentModificationException`. Use `Iterator.remove()`, `removeIf()`, or build a new collection.

  • `float` and `double` for money

    Binary floating point cannot represent 0.1 exactly, so currency arithmetic drifts. Use `BigDecimal` — and construct it from a string, not a double.

  • Returning `null` from a collection method

    It forces every caller into a null check they will eventually forget. Return an empty collection, or `Optional` for a single value that may be absent.

  • Catching `Exception` and logging nothing

    `catch (Exception e) {}` turns a diagnosable failure into a mystery. Catch what you can handle, log with the stack trace, and let the rest propagate.

In production

Where it is running at scale, and what it is doing there.

  • Amazon

    Backend services, cloud computing, and large-scale distributed systems.

  • LinkedIn

    Enterprise backend services and web applications.

  • Netflix

    Microservices architecture and high-performance streaming services.

  • Uber

    Backend services and real-time dispatch system.

Learning path

A realistic order to learn things in, with something to build at each step.

  1. 1

    Weeks 1–2

    Language core

    Types and variables, control flow, methods, classes and objects, arrays, and the difference between primitives and references. Get comfortable reading a stack trace early — you will read thousands.

    Build this: Write a console application that models a small domain, such as a library with books and borrowers.

  2. 2

    Weeks 3–4

    Object orientation and collections

    Interfaces, inheritance, composition, generics, and the Collections Framework — `List`, `Map`, `Set` and when each is the right choice. Learn `equals`/`hashCode` properly; hash-based collections depend on them.

    Build this: Replace your arrays with the right collection types and justify each choice.

  3. 3

    Month 2

    Modern Java and tooling

    Lambdas, streams, `Optional`, records, `var`, the `java.time` API, plus Maven or Gradle, JUnit 5 and your IDE's debugger. This is the step that separates Java-8-era code from current code.

    Build this: Add a Maven build and JUnit tests, and rewrite your loops as stream pipelines where it improves clarity.

  4. 4

    Months 3–4

    Building real services

    Spring Boot for web APIs and dependency injection, JPA or jOOQ for the database, Jackson for JSON, and SLF4J for logging. Learn what dependency injection is solving before learning its annotations.

    Build this: Build a REST API with a database behind it, integration-tested with Testcontainers.

  5. 5

    Ongoing

    The JVM itself

    Concurrency and virtual threads, garbage-collector behaviour and tuning, profiling with JFR and async-profiler, and reading bytecode when a puzzle demands it. This knowledge is what makes a senior Java developer.

    Build this: Load-test your API, profile it, and fix the bottleneck you find rather than the one you assumed.

Ecosystem and tooling

The tools you will end up installing whichever project you join.

ToolWhat it does
Maven / GradleBuild, dependency resolution and packaging; Maven for convention, Gradle for flexibility
Spring BootThe dominant application framework — web, security, data access and configuration in one
IntelliJ IDEAThe reference IDE; its refactoring and debugging are a large part of Java's productivity story
JUnit 5 + MockitoStandard unit testing and mocking
TestcontainersRuns real databases and brokers in Docker for integration tests instead of fakes
OpenJDK buildsTemurin, Corretto, Zulu and others — free, production-grade JDK distributions
GraalVMAhead-of-time compilation to native binaries with millisecond startup and low memory use
JFR + async-profilerLow-overhead production profiling for CPU, allocation and lock contention

Java libraries

74 catalogued, each with installation, worked examples and best practices.

Frequently asked

Is Java still worth learning in 2026?

Yes, if back-end, enterprise or Android work interests you. Java runs an enormous share of banking, insurance, retail and logistics systems, and those systems are not being rewritten. The job market is large, stable and well paid, and the modern language is far more pleasant than its reputation.

Which version should I use?

The most recent LTS — Java 21 or 25 — for anything new. If you are joining an existing codebase, expect Java 8, 11 or 17 and check before copying examples: records, `var` and pattern matching will not compile on older versions.

Java or Kotlin?

Kotlin is more concise, has null safety in the type system and is the default for Android. Java has a larger talent pool, simpler tooling and better backwards compatibility. They interoperate freely on the JVM, so the decision is rarely permanent and often team preference.

Do I need Spring?

Not to learn Java, and you should not start with it. For production web services it is the default in most organisations, and its ecosystem — Spring Security, Spring Data, Spring Cloud — is why. Quarkus and Micronaut are lighter alternatives with faster startup.

Is the JVM slow?

The opposite, for long-running processes: the JIT compiler optimises using real runtime behaviour, which an ahead-of-time compiler cannot observe. What is slow is *starting* — warm-up costs make it a poor fit for short-lived CLI tools unless you compile with GraalVM.

Do virtual threads replace reactive programming?

For most applications, yes. The main reason teams adopted reactive stacks was thread-per-request exhaustion under load, and virtual threads solve that while keeping code readable and stack traces meaningful. Reactive still wins where you genuinely need backpressure and stream composition.