杰瑞科技汇

Java list contains如何高效判断元素存在?

Of course! The List.contains() method is a fundamental operation in Java for checking if an element exists within a List. Here's a comprehensive guide covering its usage, behavior, performance, and best practices.

Java list contains如何高效判断元素存在?-图1
(图片来源网络,侵删)

Basic Usage

The contains() method is used to check if a specified element is present in the List. It returns a boolean value:

  • true if the list contains the specified element.
  • false otherwise.

Syntax

boolean contains(Object element)

Simple Example

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ContainsExample {
    public static void main(String[] args) {
        // Create a list of strings
        List<String> fruits = new ArrayList<>(Arrays.asList("Apple", "Banana", "Orange", "Mango"));
        // Check for an element that exists
        boolean hasApple = fruits.contains("Apple");
        System.out.println("Does the list contain 'Apple'? " + hasApple); // Output: true
        // Check for an element that does not exist
        boolean hasGrape = fruits.contains("Grape");
        System.out.println("Does the list contain 'Grape'? " + hasGrape); // Output: false
    }
}

How contains() Works: The equals() Contract

This is the most important concept to understand about contains(). The contains() method internally uses the equals() method of the objects to perform the comparison.

This means that for list.contains(obj) to return true, at least one element e in the list must satisfy the condition e.equals(obj).

Example with Custom Objects

This behavior becomes critical when you work with your own custom classes. If you don't override the equals() method, Java will use the default implementation from the Object class, which checks for reference equality (i.e., whether two variables point to the exact same object in memory).

Java list contains如何高效判断元素存在?-图2
(图片来源网络,侵删)

Let's see this in action.

Case 1: Using the default equals() (Reference Equality)

import java.util.ArrayList;
import java.util.List;
class User {
    private String name;
    private int id;
    public User(String name, int id) {
        this.name = name;
        this.id = id;
    }
    // Getters
    public String getName() { return name; }
    public int getId() { return id; }
    // Note: We are NOT overriding equals() and hashCode()
}
public class UserContainsExample {
    public static void main(String[] args) {
        List<User> users = new ArrayList<>();
        User user1 = new User("Alice", 101);
        users.add(user1);
        // Create a new User object with the same data
        User user2 = new User("Alice", 101);
        // This will print false because user1 and user2 are two different objects in memory.
        // The default equals() compares memory addresses, not content.
        System.out.println("Does the list contain user2? " + users.contains(user2)); // Output: false
    }
}

Case 2: Overriding equals() (Content Equality)

To fix the above, you must override the equals() method in your custom class to define what "equality" means for your objects. It's also a best practice to override hashCode() whenever you override equals().

Java list contains如何高效判断元素存在?-图3
(图片来源网络,侵删)
import java.util.ArrayList;
import java.util.List;
class User {
    private String name;
    private int id;
    public User(String name, int id) {
        this.name = name;
        this.id = id;
    }
    // Getters
    public String getName() { return name; }
    public int getId() { return id; }
    // Override equals() to define logical equality
    @Override
    public boolean equals(Object o) {
        // 1. Check if it's the exact same object
        if (this == o) return true;
        // 2. Check if the other object is null or of a different class
        if (o == null || getClass() != o.getClass()) return false;
        // 3. Cast and compare relevant fields
        User user = (User) o;
        return id == user.id && name.equals(user.name);
    }
    // IMPORTANT: Override hashCode() to maintain the general contract:
    // If a.equals(b) is true, then a.hashCode() must equal b.hashCode().
    @Override
    public int hashCode() {
        return name.hashCode() + Integer.hashCode(id);
    }
}
public class UserContainsExampleFixed {
    public static void main(String[] args) {
        List<User> users = new ArrayList<>();
        User user1 = new User("Alice", 101);
        users.add(user1);
        User user2 = new User("Alice", 101);
        // Now this will print true because our custom equals() method
        // compares the content (name and id) and finds them to be equal.
        System.out.println("Does the list contain user2? " + users.contains(user2)); // Output: true
    }
}

Performance Considerations

The performance of contains() depends entirely on the type of List you are using.

ArrayList and Vector

These implementations use an array to store elements. To check if an element exists, contains() must iterate through the array one by one until it finds a match or reaches the end.

  • Time Complexity: O(n) (where 'n' is the number of elements in the list).
  • This is inefficient for very large lists if you need to perform many contains() checks.

LinkedList

This implementation uses a doubly-linked list. Like ArrayList, it must also iterate from the beginning (or the end) to find the element.

  • Time Complexity: O(n).
  • While it has the same theoretical complexity as ArrayList, in practice, ArrayList is often faster for random access and containment checks due to the lower overhead of array access compared to traversing node links.

HashSet and HashMap (The Better Alternative for Frequent Lookups)

If your primary use case is to frequently check for the existence of elements and you don't need to maintain the order of insertion, you should use a Set instead of a List.

  • HashSet uses a HashMap internally.
  • It stores elements based on their hashCode() and uses a hash table for lookups.
  • Time Complexity for contains(): O(1) on average. This is significantly faster than O(n).
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
public class PerformanceExample {
    public static void main(String[] args) {
        List<String> fruitList = new ArrayList<>(Arrays.asList("Apple", "Banana", "Orange", "Mango"));
        HashSet<String> fruitSet = new HashSet<>(fruitList);
        // --- Checking for an element that exists ---
        long startTime, endTime;
        // List.contains()
        startTime = System.nanoTime();
        boolean listResult = fruitList.contains("Orange");
        endTime = System.nanoTime();
        System.out.println("List.contains() took: " + (endTime - startTime) + " ns");
        // Set.contains()
        startTime = System.nanoTime();
        boolean setResult = fruitSet.contains("Orange");
        endTime = System.nanoTime();
        System.out.println("Set.contains() took: " + (endTime - startTime) + " ns");
        System.out.println("List result: " + listResult);
        System.out.println("Set result: " + setResult);
    }
}

(Note: The exact timings will vary, but you will consistently see that the HashSet lookup is orders of magnitude faster, especially as the collection grows.)


Checking for null

The contains() method can also be used to check if the list contains a null element. It handles this gracefully without throwing a NullPointerException.

import java.util.ArrayList;
import java.util.List;
public class NullContainsExample {
    public static void main(String[] args) {
        List<String> items = new ArrayList<>();
        items.add("Hello");
        items.add(null); // Add a null element
        items.add("World");
        // Check for null
        boolean hasNull = items.contains(null);
        System.out.println("Does the list contain null? " + hasNull); // Output: true
        // Check for a non-null element
        boolean hasHello = items.contains("Hello");
        System.out.println("Does the list contain 'Hello'? " + hasHello); // Output: true
    }
}

Summary

Feature Description
Purpose Checks if a list contains a specific element.
Return Type boolean (true if found, false otherwise).
Mechanism Internally uses the equals() method of the elements.
Key Takeaway For custom objects, you must override equals() for contains() to work as expected.
Performance O(n) for ArrayList and LinkedList. Use a HashSet for O(1) average time complexity if frequent lookups are needed.
Null Handling Works correctly to check for the presence of null elements.
分享:
扫描分享到社交APP
上一篇
下一篇