Generics in Java: Writing Flexible Code Without (ClassCastException)

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Generics in Java: How to Stop Fearing Angle Brackets and Start Writing Reliable Code

\n\n

In the world of Java, there is one thing that frightens beginners almost as much as multithreading — angle brackets <>. Generics look mysterious, but in reality, they are your main ally in the fight for clean and safe code. Let's figure out how typing in Java works with examples you can apply today.

\n\n

Imagine: you are writing a method that should work with numbers, strings, and your own classes. Without generics, you would have to create dozens of overloaded methods or use Object and constantly check types manually. Java generics solve this problem elegantly and safely.

\n\n

Why Does Code Without Generics Become a Minefield?

\n\n

Let's recall how programmers lived before generics appeared (before Java 5). If you've ever written an ArrayList without specifying a type, you know this nightmare:

\n\n
List list = new ArrayList();\nlist.add("Hello");\nlist.add(42);\nlist.add(new Object());\n\n// Somewhere 100 lines later:\nString text = (String) list.get(1); // ClassCastException at runtime!
\n\n

A classic problem: ClassCastException — an error that only appears during execution. You could pass the list to another method, and someone there is sure it only contains strings. And boom! The application crashes. Generics in Java move type checking to the compilation stage — it's like insurance that works before you get behind the wheel.

\n\n

Generics in Java: Basic Syntax You Need to Know

\n\n

At the core of generics is a simple idea: we parameterize a class or method with a type. Instead of a specific type, we write a type parameter (usually a single uppercase letter: T, E, K, V).

\n\n

The most popular example is Java collections:

\n\n
// Without generics — dangerous\nList rawList = new ArrayList();\n\n// With generics — safe\nList<String> safeList = new ArrayList<>();\nsafeList.add("Java");\nsafeList.add("Generics");\n// safeList.add(123); // Compilation error!
\n\n

The compiler now knows: inside safeList there can only be strings. An attempt to add a number will cause an error at compile time, not at runtime. This is Java type safety in action.

\n\n

Creating Your First Generic Class

\n\n

Let's say we are writing a simple container for storing one value. Without generics, we would have to use Object:

\n\n
public class Box {\n    private Object value;\n\n    public void set(Object value) { this.value = value; }\n    public Object get() { return value; }\n}
\n\n

And now — with generics:

\n\n
public class Box<T> {\n    private T value;\n\n    public void set(T value) { this.value = value; }\n    public T get() { return value; }\n}\n\n// Usage:\nBox<Integer> intBox = new Box<>();\nintBox.set(100);\nint value = intBox.get(); // Without casting!
\n\n

Notice: we no longer need to write (Integer) intBox.get(). The compiler itself knows that get() will return an Integer. This is the magic of Java generics.

\n\n

Typing in Java: Bounds and Wildcards

\n\n

Generics would be too simple if there were no nuances. The main one is bounded type parameters. Sometimes you need to say: "Type T must be a number" or "T must implement the Comparable interface".

\n\n
// T can only be Number or its subclass\npublic class Calculator<T extends Number> {\n    private T value;\n\n    public double square() {\n        return value.doub                

Blogs

Book Recommendations