杰瑞科技汇

Collection在Java中如何正确使用?

Of course! Let's dive deep into Java Collections. This is a fundamental and crucial topic in Java programming.

Collection在Java中如何正确使用?-图1
(图片来源网络,侵删)

What are Java Collections?

In simple terms, Java Collections are a set of classes and interfaces that provide ways to store, manage, and manipulate groups of objects (also called elements). Before collections, Java had arrays, but arrays had limitations:

  • Fixed Size: You couldn't change their size after creation.
  • No Built-in Functionality: You had to write your own code for sorting, searching, or inserting elements.

The Java Collections Framework (JCF) was created to solve these problems and provide a robust, standardized, and efficient way to handle groups of objects.


The Core Architecture: Interfaces, Classes, and Algorithms

The framework is built around three main components:

  1. Interfaces: Abstract data types that represent different kinds of collections. They define the behavior (what you can do with a collection).
  2. Classes: Concrete implementations of the interfaces. They provide the actual structure (how the data is stored).
  3. Algorithms: Static utility methods that perform useful operations, like sorting or searching, on objects that implement the collection interfaces. (e.g., Collections.sort()).

The Core Interfaces

These are the building blocks of the framework.

Collection在Java中如何正确使用?-图2
(图片来源网络,侵删)
Interface Description Common Implementations Key Characteristics
Collection The root interface of the collection hierarchy. It's rarely used directly. - The base for all other collection interfaces.
List An ordered collection (also known as a sequence). Elements can be accessed by their integer index (position). ArrayList, LinkedList, Vector - Ordered: Maintains insertion order.
- Allows Duplicates: Can have multiple null elements.
- Indexed: Access elements by position (e.g., list.get(0)).
Set A collection that cannot contain duplicate elements. HashSet, LinkedHashSet, TreeSet - No Duplicates: Each element is unique.
- Unordered (in HashSet): Does not maintain any order.
- Sorted (in TreeSet): Stores elements in a sorted natural order or using a custom Comparator.
Queue A collection designed for holding elements before processing. It follows the First-In-First-Out (FIFO) principle. LinkedList, PriorityQueue - FIFO: The element that was inserted first is removed first (LinkedList).
- Priority-based: Elements are removed based on priority (natural or custom), not insertion order (PriorityQueue).
Deque A "double-ended queue," meaning you can add or remove elements from both ends. ArrayDeque, LinkedList - Dual-ended: Supports insertion and removal at both the head and tail.
- Can be used as a stack, a queue, or a general-purpose double-ended queue.
Map (Not a true Collection, but part of the framework). An object that maps keys to values. A key must be unique. HashMap, LinkedHashMap, TreeMap, Hashtable - Key-Value Pairs: Stores data as a pair.
- Unique Keys: Keys cannot be duplicated.
- Fast Lookups: Extremely efficient for retrieving values by their key.

Common Concrete Classes

Let's look at the most frequently used classes and when to use them.

List Implementations

  • ArrayList

    • How it works: Backed by a dynamic array. It's like an array that can grow and shrink automatically.
    • Pros:
      • Fast Random Access: Retrieving an element by its index (get(i)) is very fast (O(1) time complexity).
      • Generally Faster: It's often the fastest implementation for most operations.
    • Cons:
      • Slow Insertion/Deletion in the Middle: Adding or removing an element in the middle of the list is slow because it requires shifting all subsequent elements (O(n) time complexity).
    • When to use: When you need fast random access and don't frequently insert or delete elements from the middle of the list. This is the default choice for most use cases.
  • LinkedList

    • How it works: Backed by a doubly-linked list. Each element (node) holds a reference to the next and previous elements.
    • Pros:
      • Fast Insertion/Deletion: Adding or removing elements from the beginning, middle, or end is very fast (O(1) time complexity if you have the node reference).
    • Cons:
      • Slow Random Access: Retrieving an element by its index is slow because it has to traverse the list from the beginning (O(n) time complexity).
    • When to use: When you need to frequently add or remove elements from anywhere in the list, especially from the front.

Set Implementations

  • HashSet

    Collection在Java中如何正确使用?-图3
    (图片来源网络,侵删)
    • How it works: Backed by a hash table. It uses the hashCode() of the objects to store them, which provides very fast lookups.
    • Pros:
      • Extremely Fast: Adding, removing, and checking for the existence of an element is very fast on average (O(1) time complexity).
    • Cons:
      • Unordered: Does not maintain any insertion order.
    • When to use: When you need to store a unique set of items and fast performance is more important than order. This is the default choice for a Set.
  • LinkedHashSet

    • How it works: Similar to HashSet, but it maintains a linked list of the entries to preserve insertion order.
    • Pros:
      • Fast + Ordered: Combines the speed of a HashSet with the benefit of maintaining insertion order.
    • Cons:
      • Slightly slower than HashSet due to the overhead of maintaining the linked list.
    • When to use: When you need a unique set of items and you must preserve the order in which they were added.
  • TreeSet

    • How it works: Backed by a TreeMap (which is a Red-Black tree). It stores elements in a sorted order.
    • Pros:
      • Sorted: Elements are always in ascending order (natural order or a custom Comparator).
    • Cons:
      • Slower: Operations are slower than HashSet (O(log n) time complexity).
      • Elements must be comparable: Objects must implement the Comparable interface, or you must provide a Comparator.
    • When to use: When you need a unique set of items that must always be in a sorted order.

Map Implementations

  • HashMap

    • How it works: The most common Map implementation. Uses a hash table to store key-value pairs.
    • Pros:
      • Extremely Fast: Adding, retrieving, and removing key-value pairs is very fast (O(1) on average).
    • Cons:
      • Unordered: Does not guarantee any order of keys.
    • When to use: For general-purpose key-value storage where performance is critical and order doesn't matter. This is the default choice for a Map.
  • LinkedHashMap

    • How it works: Like HashMap, but it maintains the insertion order of keys.
    • Pros:
      • Fast + Ordered: Fast performance while preserving the order in which keys were inserted.
    • Cons:
      • Slightly slower than HashMap.
    • When to use: When you need a Map and the order of insertion is important (e.g., implementing an LRU cache).
  • TreeMap

    • How it works: Stores keys in a sorted order based on their natural ordering or a custom Comparator.
    • Pros:
      • Sorted Keys: Keys are always in sorted order.
    • Cons:
      • Slower: Operations are slower (O(log n)).
      • Keys must be comparable.
    • When to use: When you need a Map where the keys must always be in a sorted order (e.g., a phone book).

Code Examples

Creating and Using an ArrayList

import java.util.ArrayList;
import java.util.List;
public class ListExample {
    public static void main(String[] args) {
        // Create an ArrayList of Strings
        List<String> fruits = new ArrayList<>();
        // Add elements
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Orange");
        fruits.add("Apple"); // Duplicates are allowed
        System.out.println("Initial list: " + fruits); // [Apple, Banana, Orange, Apple]
        // Get an element by index
        String firstFruit = fruits.get(0);
        System.out.println("First fruit: " + firstFruit); // Apple
        // Remove an element
        fruits.remove("Banana");
        System.out.println("List after removing Banana: " + fruits); // [Apple, Orange, Apple]
        // Get the size of the list
        System.out.println("Size of the list: " + fruits.size()); // 3
    }
}

Creating and Using a HashSet

import java.util.HashSet;
import java.util.Set;
public class SetExample {
    public static void main(String[] args) {
        // Create a HashSet of Integers
        Set<Integer> numbers = new HashSet<>();
        // Add elements
        numbers.add(10);
        numbers.add(20);
        numbers.add(5);
        numbers.add(10); // Duplicate element will be ignored
        System.out.println("Set of numbers: " + numbers); // Output might be [5, 20, 10] (order is not guaranteed)
        // Check if an element exists
        if (numbers.contains(20)) {
            System.out.println("20 is in the set.");
        }
        // Remove an element
        numbers.remove(5);
        System.out.println("Set after removing 5: " + numbers); // [20, 10]
        // Get the size
        System.out.println("Size of the set: " + numbers.size()); // 2
    }
}

Creating and Using a HashMap

import java.util.HashMap;
import java.util.Map;
public class MapExample {
    public static void main(String[] args) {
        // Create a HashMap of String keys and Integer values
        Map<String, Integer> ages = new HashMap<>();
        // Put key-value pairs
        ages.put("Alice", 30);
        ages.put("Bob", 25);
        ages.put("Charlie", 35);
        System.out.println("Map of ages: " + ages); // Output might be {Charlie=35, Alice=30, Bob=25} (order not guaranteed)
        // Get a value by its key
        int aliceAge = ages.get("Alice");
        System.out.println("Alice's age is: " + aliceAge); // 30
        // Check if a key exists
        if (ages.containsKey("Bob")) {
            System.out.println("Bob is in the map.");
        }
        // Remove a key-value pair
        ages.remove("Charlie");
        System.out.println("Map after removing Charlie: " + ages); // {Alice=30, Bob=25}
        // Get the size (number of key-value pairs)
        System.out.println("Size of the map: " + ages.size()); // 2
    }
}

Generics and Collections

Generics are a cornerstone of modern Java collections. They allow you to specify the type of objects a collection can hold, providing type safety at compile time.

  • Before Generics (Raw Types):

    List list = new ArrayList();
    list.add("Hello");
    list.add(123); // This compiles but will cause a runtime error!
    String str = (String) list.get(0); // Manual casting required
  • With Generics (The Modern Way):

    // The list can only hold Strings
    List<String> list = new ArrayList<>();
    list.add("Hello");
    // list.add(123); // COMPILE ERROR! This is caught by the compiler.
    String str = list.get(0); // No casting needed!

Using generics is highly recommended as it prevents ClassCastException and makes your code cleaner and more readable.


Summary: Which Collection Should I Use?

If you need... And you care about... Use...
A group of items in a specific order Fast access by index ArrayList
A group of items in a specific order Fast insertion/deletion LinkedList
A group of unique items, order doesn't matter Maximum speed HashSet
A group of unique items, in insertion order Order + Speed LinkedHashSet
A group of unique items, always sorted Sorting TreeSet
Key-value pairs, order doesn't matter Maximum speed HashMap
Key-value pairs, in insertion order Order + Speed LinkedHashMap
Key-value pairs, keys always sorted Sorting keys TreeMap
A first-in, first-out (FIFO) list Fast operations at both ends LinkedList or ArrayDeque
A last-in, first-out (LIFO) stack Fast operations at one end ArrayDeque (preferred over Stack class)
分享:
扫描分享到社交APP
上一篇
下一篇