What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
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").
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
Ethroughout.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
Tkeeps it independent of the outer class. - A decided empty-stack contract. Using
nullinternally as the empty marker is fine, but the public API must pick a behavior and document it. This sketch throwsEmptyStackException. The alternative is a non-throwing result, such as returningOptional<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.
Rank #2
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.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsWhat 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()ornew E[n]. - You cannot test
item instanceof E. - A
CustomStack<String>and aCustomStack<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.
Rank #4
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:
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Best Value
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
Ein every signature that touches elements. - Never write raw
Nodeor rawCustomStack; 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()andpeek(). - Compile with
-Xlint:uncheckedand 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.
Quick Recap
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.




