Skip to content
Java getting started 7 min read

Features of Java

Java was designed from the ground up with a specific set of goals: write code once and run it anywhere, make memory management automatic, keep the language safe and robust, and support concurrent programming natively. These goals translate directly into the features you will use every day.

1. Platform Independence (Write Once, Run Anywhere)

This is Java’s most famous feature. When you compile a .java file, javac produces .class files containing bytecode — an intermediate representation that is not tied to any CPU or operating system. The JVM on each target platform interprets (and JIT-compiles) that same bytecode.

public class PlatformDemo {
    public static void main(String[] args) {
        System.out.println("Running on: " + System.getProperty("os.name"));
        System.out.println("JVM version: " + System.getProperty("java.version"));
    }
}

Output (example on Linux):

Running on: Linux
JVM version: 21.0.3

The exact same .class file produces equivalent output on Windows or macOS — only the first line changes. See How a Java Program Runs for the full compilation-to-execution story.

2. Object-Oriented Programming

Java is built entirely around objects — instances of classes that combine state (fields) and behaviour (methods). The four pillars — encapsulation, inheritance, polymorphism, and abstraction — are first-class citizens of the language.

public class Animal {
    private String name; // encapsulation: private field

    public Animal(String name) { this.name = name; }

    public void speak() { System.out.println(name + " makes a sound."); }
}

public class Dog extends Animal { // inheritance
    public Dog(String name) { super(name); }

    @Override
    public void speak() { System.out.println("Woof!"); } // polymorphism
}

Tip: Everything in Java lives inside a class — even the main method. This is different from languages like C or Python where top-level functions exist outside any class.

Explore these ideas in depth starting at OOP Concepts.

3. Strongly Typed and Statically Typed

Every variable and expression in Java has a type known at compile time. The compiler rejects type mismatches before your program ever runs, catching a whole category of bugs early.

int count = 10;
String message = "hello";

// This won't compile — the compiler catches the error immediately:
// count = message; // ❌ incompatible types: String cannot be converted to int

Java 10 introduced the var keyword for local variable type inference, which lets the compiler infer the type without sacrificing static typing:

var list = new java.util.ArrayList<String>(); // type is still ArrayList<String> at compile time
list.add("Java");

Learn more in Java 10: var and Data Types.

4. Automatic Memory Management (Garbage Collection)

Java manages heap memory for you. You create objects with new; when no more references to an object exist, the Garbage Collector (GC) reclaims that memory automatically. There is no free() or delete.

public class GCDemo {
    public static void main(String[] args) {
        for (int i = 0; i < 1_000_000; i++) {
            String s = new String("object " + i); // created and quickly becomes unreachable
        }
        // No memory leak — the GC cleans up unreachable objects automatically
        System.out.println("Done — no manual cleanup needed.");
    }
}

Output:

Done — no manual cleanup needed.

The modern GC implementations (G1, ZGC, Shenandoah) in Java 21 can handle heaps of hundreds of gigabytes with sub-millisecond pause times. See Garbage Collection Deep-Dive for tuning strategies.

5. Multithreading

Java has built-in language and library support for running multiple threads concurrently. The Thread class and Runnable interface have been in Java since version 1.0, and Java 21 adds virtual threads (Project Loom) that make concurrent I/O-bound code dramatically simpler and cheaper.

public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> System.out.println("Thread 1 running"));
        Thread t2 = new Thread(() -> System.out.println("Thread 2 running"));
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

Output (order may vary):

Thread 1 running
Thread 2 running

Note: The output order is non-deterministic — the OS thread scheduler decides which thread runs first.

Explore the full threading model in Multithreading and Virtual Threads.

6. Robust and Reliable

Java was designed to catch errors as early as possible. Three mechanisms work together:

  • Compile-time type checking — the compiler enforces types and catches obvious mistakes.
  • Exception handling — the try-catch-finally block forces you to acknowledge that operations can fail.
  • No pointers — you work with references, not raw memory addresses, eliminating segfaults and buffer overflows.
public class RobustDemo {
    public static int divide(int a, int b) {
        if (b == 0) throw new ArithmeticException("Cannot divide by zero");
        return a / b;
    }

    public static void main(String[] args) {
        try {
            System.out.println(divide(10, 0));
        } catch (ArithmeticException e) {
            System.out.println("Caught: " + e.getMessage());
        }
    }
}

Output:

Caught: Cannot divide by zero

7. Secure

Java’s security model operates at multiple levels:

  • Bytecode verifier — the JVM checks that loaded bytecode obeys type safety rules before executing it.
  • Class loader — isolates classes from different sources (see Class Loaders & Class Loading).
  • Security Manager (legacy) / module system (Java 9+) — restricts what code can access at runtime.
  • No direct memory access — pointer arithmetic is impossible, removing entire classes of exploits.

8. High Performance via JIT Compilation

Java is often described as “slow” — a reputation it outgrew years ago. The HotSpot JIT compiler monitors which methods execute most frequently (“hot spots”) and compiles them to optimised native machine code at runtime. Long-running Java services frequently match or exceed the throughput of equivalent C++ applications.

public class JITDemo {
    public static long sum(long n) {
        long total = 0;
        for (long i = 1; i <= n; i++) total += i;
        return total;
    }

    public static void main(String[] args) {
        // After a few warm-up iterations the JIT kicks in and this gets very fast
        for (int i = 0; i < 5; i++) {
            long start = System.nanoTime();
            long result = sum(100_000_000L);
            long elapsed = System.nanoTime() - start;
            System.out.printf("sum=%d  time=%dms%n", result, elapsed / 1_000_000);
        }
    }
}

You will typically see the elapsed time drop across iterations as the JIT warms up. Dive deeper in JIT Compilation & Bytecode.

9. Rich Standard Library

The Java Class Library (JCL) ships with the JDK and covers an enormous surface area out of the box:

PackageWhat it provides
java.utilCollections, Date/Time, Random, Scanner
java.io / java.nioFile I/O, channels, memory-mapped files
java.netSockets, URL handling, HTTP
java.util.concurrentThread pools, locks, atomic variables
java.util.streamFunctional-style data pipelines
java.sqlJDBC database connectivity
java.lang.reflectReflection and dynamic class inspection

You rarely need a third-party library for basic tasks. Explore the collections side in Collections Framework and streams in Stream API.

10. Distributed and Network-Friendly

Java was built with networking in mind. Socket Programming, RMI (Remote Method Invocation), and HttpURLConnection / HttpClient (Java 11+) are all part of the standard library. Java EE (now Jakarta EE) and frameworks like Spring Boot run the majority of the world’s enterprise web services.

11. Dynamic and Extensible

Despite being statically typed, Java supports dynamic loading — classes can be loaded at runtime without recompilation. This powers plugin architectures, dependency injection frameworks (Spring, Guice), and application servers that deploy new code without restarting.

// Load and instantiate a class by name at runtime
Class<?> clazz = Class.forName("java.util.ArrayList");
Object instance = clazz.getDeclaredConstructor().newInstance();
System.out.println(instance.getClass().getSimpleName()); // ArrayList

Output:

ArrayList

See Reflection API for the full picture.

Under the Hood

Several features that look like “language magic” are actually implemented at the JVM level:

  • Platform independence relies on a strict bytecode specification. Every JVM implementation — Oracle HotSpot, OpenJ9, GraalVM — must execute the same bytecode identically.
  • Garbage collection uses a generational heap: most objects die young (collected cheaply in the young generation), while survivors are promoted to the old generation and collected less often.
  • Multithreading maps Java threads to OS threads (1:1) by default. Java 21 virtual threads use a M:N mapping — millions of virtual threads multiplex over a small pool of carrier (OS) threads, making high-concurrency I/O workloads practical without async/callback complexity.
  • JIT compilation goes beyond simple translation: it inlines methods, eliminates dead code, performs escape analysis to allocate some objects on the stack instead of the heap, and speculatively optimises based on runtime type feedback.

These mechanics explain why Java code that looks expensive (lots of small object allocations, heavy use of interfaces) often performs better than you would expect.

Quick Reference

FeatureKey benefit
Platform independenceOne .jar runs on any OS / CPU
Object-orientedModels real-world complexity naturally
Strong static typingBugs caught at compile time
Automatic GCNo manual memory management
MultithreadingConcurrent code built into the language
Robust exceptionsForces explicit error handling
SecurityBytecode verification + no raw pointers
JIT performanceNative-speed execution for hot code
Rich standard libraryBatteries included for most tasks
Dynamic class loadingPlugins, DI frameworks, hot deployment
  • History of Java — understand why Java was designed this way and how it evolved over 30 years.
  • JVM Architecture — the runtime machinery behind platform independence, JIT, and GC.
  • Garbage Collection Deep-Dive — how the G1 and ZGC collectors work and how to tune them.
  • OOP Concepts — encapsulation, inheritance, polymorphism, and abstraction explained with examples.
  • Multithreading — Java’s threading model from Thread to ExecutorService to virtual threads.
  • Java 21 LTS Features — the latest additions: virtual threads, records, sealed classes, and pattern matching.
Last updated June 13, 2026
Was this helpful?