October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PCOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk5 min

Type Safety Without Explicit Casting: Building a Custom Generic Stack in Java

Build a linked, generic Java stack whose pop() returns the right type with no caller cast, and learn what erasure and raw types do to that guarantee.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If you declare a stack as CustomStack<E> and write push(E item), pop() and peek() in terms of E, callers get their own element type back with no cast: String name = names.pop(); compiles because the compiler knows the stack holds String. This article builds that stack from linked nodes, shows where the guarantee holds, shows how raw types break it, and explains when you should use the standard library instead.

What “no explicit casting” actually means

Before generics, a general-purpose container stored Object, so every pop() needed a cast and a wrong cast failed only at runtime. A generic class moves that check to compile time. Oracle’s Dev.java material on generics describes this as stronger type checking by the compiler and reusable code that works across element types.

Two points keep expectations accurate:

  • The guarantee is mainly compile-time. Java uses type erasure: an unbounded type parameter is replaced by Object, a bounded one by its first bound, and the compiler may insert casts to keep your source type-safe (Oracle’s Java Tutorials, “Type Erasure”, written for JDK 8).
  • Those inserted casts are not casts you wrote. The caller’s code stays cast-free; the compiled code may still contain them.

The design: a linked stack of typed nodes

The stack keeps a reference to the top node and a size counter. Each node holds an E item and a reference to the node beneath it. Pushing links a new node on top; popping returns the top item and moves the top reference down; peeking reads the top item without unlinking it.

A linked design has a practical advantage for a generic teaching example: there is no array of E. Java does not let you write new E[n], so an array-backed stack typically needs (E[]) new Object[n], which is an unchecked cast and a compiler warning. Nodes avoid that entirely, so the code needs no cast and no @SuppressWarnings("unchecked").

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The implementation

The code below is an illustrative sketch of this design, written for this article rather than taken from the cited documentation.

import java.util.EmptyStackException;

public class CustomStack<E> {

    private static class Node<T> {
        final T item;
        final Node<T> next;

        Node(T item, Node<T> next) {
            this.item = item;
            this.next = next;
        }
    }

    private Node<E> top;   // null means empty (internal detail)
    private int size;

    public void push(E item) {
        top = new Node<>(item, top);
        size++;
    }

    /** @throws EmptyStackException if the stack is empty */
    public E pop() {
        if (top == null) {
            throw new EmptyStackException();
        }
        E item = top.item;
        top = top.next;
        size--;
        return item;
    }

    /** @throws EmptyStackException if the stack is empty */
    public E peek() {
        if (top == null) {
            throw new EmptyStackException();
        }
        return top.item;
    }

    public boolean isEmpty() {
        return top == null;
    }

    public int size() {
        return size;
    }
}

Why each choice matters

  • Storage typed as E throughout. Node<E> is never declared raw, so the compiler can check every link in the chain.
  • A static nested node class. It does not need the outer instance, and giving it its own parameter T keeps it independent of the outer class.
  • A decided empty-stack contract. Using null internally as the empty marker is fine, but the public API must pick a behavior and document it. This sketch throws EmptyStackException. The alternative is a non-throwing result, such as returning Optional<E> from a separate method. That is a design choice, not something the Java documentation prescribes for custom classes.

Using it without a cast

CustomStack<String> names = new CustomStack<>();
names.push("Ada");
names.push("Grace");

String top = names.pop();   // "Grace" - no cast

names.push(42);             // compile-time error: int cannot be converted to String

The last line shows the other half of the benefit: the wrong type is rejected when you compile, not when the program runs. Generic type arguments must be reference types, so a stack of numbers is CustomStack<Integer>; autoboxing lets push(42) work for that stack.

Where the guarantee breaks: raw types and unchecked warnings

Oracle’s tutorial on raw types describes them as behavior retained from before generics, warns that they bypass generic type checks, and recommends avoiding them. A raw reference lets an incompatible value slip in:

CustomStack<String> names = new CustomStack<>();
CustomStack raw = names;     // raw type: unchecked-conversion territory
raw.push(42);                // compiles, with an unchecked warning

String s = names.pop();      // ClassCastException at this line

The failure appears at the caller’s pop(), not at the bad push, which makes it harder to trace. Dev.java’s erasure material calls this situation heap pollution: a variable of a parameterized type refers to an object that is not of that type. Compile with -Xlint:unchecked to see the warnings Oracle’s tutorial points to, and treat each one as a real defect to fix rather than noise to suppress.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What erasure means for your stack

Because generic arguments are not fully available at runtime, certain things are unavailable inside CustomStack<E>:

  • You cannot write new E() or new E[n].
  • You cannot test item instanceof E.
  • A CustomStack<String> and a CustomStack<Integer> share one runtime class, so the stack cannot inspect which element type it was created with.

None of this affects the design above, which never needs to know E at runtime. It is the reason the compile-time discipline (no raw types, no casual unchecked casts) matters: nothing at runtime will enforce it for you.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Custom stack or the standard library?

The Java SE 24 API documentation for java.util.Stack describes it as a last-in-first-out stack with push, pop, peek and empty, and then says: “A more complete and consistent set of LIFO stack operations is provided by the Deque interface and its implementations, which should be used in preference to this class.”

For ordinary application code, that is the guidance to follow:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Deque<String> stack = new ArrayDeque<>();
stack.push("Ada");
String top = stack.pop();   // typed, no cast
Question Custom CustomStack<E> Deque implementation
Best purpose Learning generics and linked structures; a deliberately narrow API Production LIFO use, per the Java SE 24 documentation
API breadth Only what you write and maintain A fuller, consistent set of operations through the interface
Maintenance Yours: contract, tests, edge cases Maintained with the JDK
Type safety for callers Same compile-time guarantee when generic and used without raw types Same

This comparison is by purpose and API fit. No performance or synchronization comparison is made here, because the cited documentation does not provide one; if those matter, check the documentation of the specific class and Java version you target.

A custom stack is justified when the point is to learn, when you must expose a deliberately restricted interface (for example, no random access), or when you need behavior the JDK types do not offer.

Checklist for a type-safe generic stack

  • Declare the type parameter on the class and use E in every signature that touches elements.
  • Never write raw Node or raw CustomStack; use <> when instantiating.
  • Avoid unchecked casts and blanket @SuppressWarnings("unchecked"); prefer a design, like linked nodes, that needs neither.
  • Document the empty-stack behavior of pop() and peek().
  • Compile with -Xlint:unchecked and resolve every warning.

For deeper study of the rules behind unchecked conversion, see the Java Language Specification and Oracle’s Dev.java generics lessons. A general Java generics or data-structures textbook can also help, but nothing here requires one or any particular IDE.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.