Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Java Collections Framework: Interfaces, Data Structures, and Generics

Tech May 19 1

Java Collections Framework

1. Collection Interface

1.1 Arrays vs Collections

Similarities:

  • Both are containers for storing multiple elements

Differences:

    li>Array size is fixed, while collections can dynamically resize
  • Arrays can store both primitive data types and objects
  • Collections only store objects (primitives must use their wrapper classes)

1.2 Collection Class Hierarchy

1.3 Collection Interface Overview

The Collection interface is the root interface in the collection hierarchy. It represents a group of objects, known as elements. The Java Development Kit (JDK) doesn't provide any direct implementations of this interface; instead, it offers more specific subinterfaces like Set and List.

To create a Collection instance, use polymorphism with a concrete implementation class such as ArrayList:

Collection<String> collection = new ArrayList<>();

1.4 Common Collection Methods

>Returns the number of elements in the collection
Method Description
boolean add(E e) Adds an element to the collection
boolean remove(Object o) Removes a specified element from the collection
boolean removeIf(Predicate<? super E> filter) Removes elements that match the given condition
void clear() Removes all elements from the collection
boolean contains(Object o) Checks if the collection contains a specified element
boolean isEmpty() Checks if the collection is empty
int size()

1.5 Collection Iteration

The Iterator is a special traversal mechanism for collections. You obtain an iterator using the iterator() method:

Iterator<String> iterator = collection.iterator();

Iterator methods:

  • boolean hasNext(): Checks if there are more elements to iterate
  • E next(): Returns the next element and advances the iterator

Example of iterating through a collection:

Collection<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");

Iterator<String> it = names.iterator();
while (it.hasNext()) {
    String name = it.next();
    System.out.println(name);
}

Removing elements during iteration:

ArrayList<String> items = new ArrayList<>();
items.add("apple");
items.add("banana");
items.add("banana");
items.add("orange");

Iterator<String> it = items.iterator();
while(it.hasNext()) {
    String item = it.next();
    if("banana".equals(item)) {
        it.remove(); // Removes the current element
    }
}
System.out.println(items); // Output: [apple, orange]

1.6 Enhanced For Loop

Introduced in Java 5, the enhanced for loop simplifies array and collection iteration. It internally uses an Iterator.

Only classes implementing the Iterable interface can use this loop.

Syntax:

for (DataType variable : collectionOrArray) {
    // Use variable to access current element
}

Example:

ArrayList<String> fruits = new ArrayList<>();
fruits.add("apple");
fruits.add("banana");
fruits.add("cherry");

for (String fruit : fruits) {
    System.out.println(fruit);
}

2. List Interface

2.1 List Overview and Characteristics

The List interface extends Collection and represents an ordered collection (also known as a sequence). Users have precise control over where each element is inserted. Elements can be accessed by their integer index (position).

Characteristics:

    li>Ordered - maintains insertion order
  • Duplicate elements allowed
  • li>Indexed - supports positional access

2.2 List-Specific Methods

Method Description
void add(int index, E element) Inserts an element at the specified position
E remove(int index) Removes the element at the specified position and returns it
E set(int index, E element) Replaces the element at the specified position and returns the replaced element
E get(int index) Returns the element at the specified position

3. Data Structures

3.1 Stack and Queue

Stack:

    li>Last-In-First-Out (LIFO) structure
  • Elements added last are removed first

Queue:

    li>First-In-First-Out (FIFO) structure li>Elements added first are removed first

3.2 Arrays and Linked Lists

Array:

    li>Fast access by index (O(1) time complexity) li>Slow insertion/deletion (O(n) time complexity)

Linked List:

    li>Slow access by index (O(n) time complexity) li>Fast insertion/deletion (O(1) time complexity)

4. List Implementations

4.1 ArrayList vs LinkedList

ArrayList:

    li>Backed by an array li>Fast random access li>Slow insertion/deletion in the middle

LinkedList:

    li>Backed by a doubly-linked list li>Fast insertion/deletion li>Slow random access

4.2 LinkedList-Specific Methods

li>Inserts the specified element at the beginning of this list li>Appends the specified element to the end of this list li>Returns the first element in this list li>Returns the last element in this list li>Removes and returns the first element from this list li>Removes and returns the last element from this list
Method Description
void addFirst(E e)
void addLast(E e)
E getFirst()
E getLast()
E removeFirst()
E removeLast()

5. Generics

5.1 Generic Overview

Generics, introduced in Java 5, provide compile-time type safety. They allow you to define classes, interfaces, and methods with type parameters.

Benefits:

    li>Catch type errors at compile time rather than runtime li>Eliminate the need for explicit type casting

Generic syntax:

    li><Type>: Specifies a single type parameter li><Type1, Type2, ...>: Specifies multiple type parameters

5.2 Generic Classes

Definition syntax:

class ClassName<Type> { }

Example:

class Box<T> {
    private T content;
    
    public void setContent(T content) {
        this.content = content;
    }
    
    public T getContent() {
        return content;
    }
}

Usage:

Box<String> stringBox = new Box<>();
stringBox.setContent("Hello Generics");
System.out.println(stringBox.getContent());

Box<Integer> intBox = new Box<>();
intBox.setContent(123);
System.out.println(intBox.getContent());

5.3 Generic Methods

Definition syntax:

<Type> ReturnType methodName(Type param) { }

Example:

<nclass Utility {
    public &lt;T&gt; void printArray(T[] array) {
        for (T element : array) {
            System.out.print(element + " ");
        }
        System.out.println();
    }
}</code>

Usage:

Utility utility = new Utility();
Integer[] intArray = {1, 2, 3, 4, 5};
String[] strArray = {"A", "B", "C"};

utility.printArray(intArray);
utility.printArray(strArray);

5.4 Generic Interfaces

Definition syntax:

interface InterfaceName<Type> { }

Example:

interface Container<T> {
    void add(T item);
    T get(int index);
}

Implementation approaches:

  1. Define implementation with same generic type:
class ListContainer<T> implements Container<T> {
    private List<T> items = new ArrayList<>();
    
    @Override
    public void add(T item) {
        items.add(item);
    }
    
    @Override
    public T get(int index) {
        return items.get(index);
    }
}
  1. Define implementation with specific type:
class StringContainer implements Container<String> {
    private List<String> items = new ArrayList<>();
    
    @Override
    public void add(String item) {
        items.add(item);
    }
    
    @Override
    public String get(int index) {
        return items.get(index);
    }
}

5.5 Type Wildcards

Unbounded Wildcard (?):

    li>Represents an unknown type li>Can accept any type but can't add elements

Upper Bounded Wildcard (? extends Type):

    li>Accepts the specified type or its subtypes

Lower Bounded Wildcard (? super Type):

    li>Accepts the specified type or its supertypes

Example usage:

public class WildcardDemo {
    // Unbounded wildcard
    public static void printList(List<?> list) {
        for (Object elem : list) {
            System.out.print(elem + " ");
        }
        System.out.println();
    }
    
    // Upper bounded wildcard
    public static double sumOfList(List<? extends Number> list) {
        double sum = 0.0;
        for (Number num : list) {
            sum += num.doubleValue();
        }
        return sum;
    }
    
    // Lower bounded wildcard
    public static void addNumbers(List<? super Integer> list) {
        for (int i = 1; i <= 5; i++) {
            list.add(i);
        }
    }
}

Difference between wildcards and type parameters:

    li>Type parameters (T) must be declared before the return type li>Wildcards (?) can be used directly without declaration
// Type parameter approach
private static <T> void processList(List<T> list) { }

// Wildcard approach
private static void processList(List<?> list) { }
Tags: Java

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.