Java Generics And Collections

Understanding Generics in Java

Generics in Java allow you to use type parameters in your code, providing flexibility and type safety. Here’s a detailed explanation of how they work:

Defining Generics

To create a class with a generic parameter, use the syntax <T> after the class name. The parameter name can be any valid identifier, but single uppercase letters like T, E, or K are common.

Example: class Box<T> { }

The Diamond Operator (<>)

The diamond operator simplifies generic declarations by inferring the type from the context. It can be used with local variables, instance variables, and one-line declarations.

Example: Box<String> box = new Box<>();

Wildcards in Generics

  • <?>: Unbounded wildcard, meaning any type.
  • <? extends Object>: Upper bound, allowing any type that is Object or its subclass.
  • <? extends MyInterface>: Upper bound for types implementing MyInterface.
  • <? super Number>: Lower bound, allowing Number or its superclasses.

Note: Attempting to add or remove items from a list with an unbounded or upper-bounded wildcard results in a compiler error.

Generics and Legacy Code

When working with raw types or legacy code without generics, Java issues a compiler warning. Ignoring these warnings can lead to runtime ClassCastException. Unboxing without generics results in compiler errors.

Autoboxing and Unboxing

Java can convert between primitive types and their wrapper classes automatically:

  • Primitive: long
  • Wrapper: Long

This is called autoboxing and unboxing. When resolving method calls, Java prioritizes primitive signatures over their object equivalents.

Example: remove(int n) will be called over remove(Object o) for an int.

Java Collections Framework

The framework includes the following data structures:

  • List: Ordered collection allowing duplicates
    • ArrayList: Resizable list
    • LinkedList: Fast add/remove from beginning or end
    • Vector: Thread-safe ArrayList
    • Stack: Last-in, first-out
  • Set: No duplicates
    • HashSet: Uses hashCode()
    • TreeSet: Sorted and navigable, no null values
  • Queue: Element processing order
    • LinkedList: Flexible add/remove
    • ArrayDeque: FIFO or LIFO, no null values
  • Map: Key-value pairs
    • HashMap: Uses hashCode() for keys
    • TreeMap: Sorted keys, no null keys
    • Hashtable: Legacy version, no null keys/values

Comparable and Comparator

Comparable: Defines the compareTo() method to compare one object.

Comparator: Defines the compare() method to compare two objects. Commonly implemented with lambdas.

Utility Methods

Key methods in the Arrays and Collections classes:

  • sort(): Sorts elements
  • binarySearch(): Searches for elements

Note: Ensure the same sort order is used for both sorting and searching.

Collection methods that take lambdas include:

  • removeIf()
  • forEach()
  • merge()

Method References

A method reference is a concise way to write lambdas referring to methods. There are four types:

  • Static methods
  • Instance methods of a specific instance
  • Instance methods with runtime-supplied instance
  • Constructor references

Post a Comment

0 Comments