ZetCode

Java Collections.frequency 方法

上次修改时间:2025 年 4 月 20 日

Collections.frequency 方法是 Java Collections 框架提供的一个实用方法。它用于计算给定集合中特定元素出现的次数。此方法是 java.util.Collections 类的一部分,它简化了诸如统计数据结构中出现的次数之类的任务。

该方法的签名是 public static int frequency(Collection<?> c, Object o)。它接受两个参数:一个集合和一个要搜索的对象。集合可以是任何实现 Collection 接口的类型,例如 ListSetQueue。该方法返回一个整数,表示集合中指定对象的总出现次数。如果集合为空或未找到指定的元素,则返回 0

Collections.frequency 的基本用法

此示例演示了 Collections.frequency 的最简单用法。我们创建一个字符串列表,并计算特定字符串出现了多少次。该方法适用于任何 Collection 实现。

BasicFrequencyExample.java
package com.zetcode;

import java.util.Collections;
import java.util.List;

public class BasicFrequencyExample {

    public static void main(String[] args) {

        List<String> colors = List.of("Red", "Green", "Blue", "Red", "Yellow");

        int redCount = Collections.frequency(colors, "Red");
        int blueCount = Collections.frequency(colors, "Blue");
        int blackCount = Collections.frequency(colors, "Black");

        System.out.println("Red appears " + redCount + " times");
        System.out.println("Blue appears " + blueCount + " times");
        System.out.println("Black appears " + blackCount + " times");
    }
}

此代码创建了一个颜色列表,其中包含一些重复项。然后,我们使用 Collections.frequency 计算“Red”、“Blue”和“Black”的出现次数。该方法返回“Red”为 2,“Blue”为 1,“Black”为 0。

该示例表明该方法正确地计算了现有元素,并为集合中不存在的元素返回 0。它区分大小写,并使用 equals() 进行比较。

计数自定义对象

此示例演示了将 Collections.frequency 与自定义对象一起使用。为了使该方法正常工作,这些对象必须正确实现 equals 方法。我们将创建一个简单的 Person 记录并计算出现的次数。

CustomObjectFrequency.java
package com.zetcode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

record Person(String name, int age) {}

public class CustomObjectFrequency {

    public static void main(String[] args) {

        List<Person> people = new ArrayList<>();
        people.add(new Person("Alice", 25));
        people.add(new Person("Bob", 30));
        people.add(new Person("Alice", 25));
        people.add(new Person("Charlie", 35));
        people.add(new Person("Alice", 30));

        Person alice25 = new Person("Alice", 25);
        Person alice30 = new Person("Alice", 30);
        Person dave40 = new Person("Dave", 40);

        System.out.println("Alice (25) appears " +
                Collections.frequency(people, alice25) + " times");
        System.out.println("Alice (30) appears " +
                Collections.frequency(people, alice30) + " times");
        System.out.println("Dave (40) appears " +
                Collections.frequency(people, dave40) + " times");
    }
}

此示例演示了如何使用记录来计算集合中自定义对象的数量。Person 记录根据其组件(例如,姓名和年龄)自动实现 equalshashCodetoString 方法。这消除了手动实现 equals 的需要,确保了 Collections.frequency 的正常功能。

我们定义了几个 Person 记录并计算特定实例的出现次数。输出显示了相同的记录(相同的姓名和年龄)被正确计数,而未匹配的记录返回 0。由于 equals 方法由记录生成,因此它在确定对象相等性方面起着至关重要的作用。

不同集合类型的频率

Collections.frequency 方法适用于任何 Collection 实现。此示例演示了它与 ArrayList、HashSet 和 LinkedList 的使用。在不同的集合类型中,行为保持一致。

DifferentCollectionTypes.java
package com.zetcode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

public class DifferentCollectionTypes {

    public static void main(String[] args) {
        
        // ArrayList example
        List<Integer> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, 1, 2, 3, 2, 4, 2, 5);
        System.out.println("ArrayList count of 2: " + 
            Collections.frequency(arrayList, 2));
        
        // HashSet example (no duplicates)
        Set<Integer> hashSet = new HashSet<>(arrayList);
        System.out.println("HashSet count of 2: " + 
            Collections.frequency(hashSet, 2));
        
        // LinkedList example
        List<Integer> linkedList = new LinkedList<>();
        Collections.addAll(linkedList, 1, 1, 1, 2, 3);
        System.out.println("LinkedList count of 1: " + 
            Collections.frequency(linkedList, 1));
    }
}

此示例显示了 Collections.frequency 与不同集合类型的配合使用。我们使用一个包含重复项的 ArrayList、一个 HashSet(它消除了重复项)和一个 LinkedList。该方法在所有实现中表现一致。

ArrayList 显示包含重复项的计数(值 2 为 3)。HashSet 无法包含重复项,显示为 0 或 1。LinkedList 演示了在另一个 List 实现中进行计数。

带有 Null 值的频率

此示例探讨了 Collections.frequency 如何处理集合中的 null 值。如果集合包含 null 值,则该方法可以计算 null 出现的次数。我们将通过不同的场景演示此行为。

NullFrequencyExample.java
package com.zetcode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class NullFrequencyExample {

    public static void main(String[] args) {
        
        List<String> words = new ArrayList<>();
        words.add("apple");
        words.add(null);
        words.add("banana");
        words.add(null);
        words.add(null);
        words.add("cherry");
        
        System.out.println("Null appears " + 
            Collections.frequency(words, null) + " times");
        
        System.out.println("\"apple\" appears " + 
            Collections.frequency(words, "apple") + " times");
        
        List<String> noNulls = new ArrayList<>();
        noNulls.add("one");
        noNulls.add("two");
        
        System.out.println("In noNulls, null appears " + 
            Collections.frequency(noNulls, null) + " times");
    }
}

此示例演示了 Collections.frequency 如何处理 null 值。我们创建一个包含几个 null 和一些字符串的列表。该方法正确地计算了 null 的出现次数(在本例中为 3)。

我们还表明,它在非 null 值下的工作方式正常,并且对于不包含 null 的集合中的 null 计数返回 0。该方法安全地处理集合中的 null 元素和作为搜索参数的 null。

性能注意事项

此示例检查 Collections.frequency 的性能特征。该方法执行线性搜索,使其具有 O(n) 复杂度。对于大型集合,这可能会影响性能。

FrequencyPerformance.java
package com.zetcode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class FrequencyPerformance {

    public static void main(String[] args) {
        
        // Create a large list
        List<Integer> numbers = new ArrayList<>();
        for (int i = 0; i < 1_000_000; i++) {
            numbers.add(i % 100); // Numbers 0-99 repeated
        }
        
        long startTime = System.nanoTime();
        int count = Collections.frequency(numbers, 50);
        long endTime = System.nanoTime();
        
        System.out.println("Count of 50: " + count);
        System.out.println("Time taken: " + 
            (endTime - startTime) / 1_000_000 + " ms");
        
        // Compare with alternative approaches
        startTime = System.nanoTime();
        long streamCount = numbers.stream().filter(n -> n == 50).count();
        endTime = System.nanoTime();
        
        System.out.println("\nStream count of 50: " + streamCount);
        System.out.println("Stream time taken: " + 
            (endTime - startTime) / 1_000_000 + " ms");
    }
}

此示例创建了一个大型列表并测量了计算出现次数所花费的时间。我们将 Collections.frequency 与 Java 8 流方法进行比较。这两种方法都具有相似的 O(n) 性能特征。

输出显示,对于大型集合,计数可能需要花费明显的时间。如果频率计数是一项频繁的操作,请考虑使用备用数据结构,例如多重集或维护单独的计数器。

具有多维集合的频率

此示例演示了如何将 Collections.frequency 与嵌套集合一起使用。该方法仅在顶层进行计数 - 它不会递归地搜索嵌套集合。我们将展示如何处理此类情况。

NestedCollectionsFrequency.java
package com.zetcode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class NestedCollectionsFrequency {

    public static void main(String[] args) {

        // Declare matrix with generic type
        List<List<Integer> matrix = new ArrayList<>();
        matrix.add(List.of(1, 2, 3));
        matrix.add(List.of(4, 5, 6));
        matrix.add(List.of(1, 2, 3));
        matrix.add(List.of(7, 8, 9));

        // Declare searchList explicitly
        List<Integer> searchList = List.of(1, 2, 3);

        // Use Collections.frequency to count occurrences of searchList in the matrix
        System.out.println("Outer list count: " +
                Collections.frequency(matrix, searchList));

        // To count all occurrences of a specific number in nested lists
        long totalCount = matrix.stream()
                .flatMap(List::stream)
                .filter(n -> n == 2) // Replace "2" with any number to search for
                .count();

        System.out.println("Total count of 2 in all lists: " + totalCount);
    }
}

此示例演示了 Collections.frequency 如何对嵌套集合进行操作。该方法计算外部集合中完整内部列表的出现次数。例如,在这种情况下,它标识了内部列表 [1, 2, 3] 的两次出现。但是,它不考虑内部列表本身的单个元素。

要在嵌套集合中搜索并计算所有内部列表中各个元素的数量,我们使用基于流的替代方法。通过使用 flatMap 展平嵌套结构,我们可以处理和过滤所有子列表中的元素。对于需要在深度嵌套数据中对搜索和计数进行细粒度控制的场景,此方法至关重要。

真实示例:词频计数器

此示例展示了 Collections.frequency 的一个实际应用 - 一个简单的词频计数器。我们将读取文本,将其拆分为单词,并计算特定单词的出现次数。

WordFrequencyCounter.java
package com.zetcode;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class WordFrequencyCounter {

    public static void main(String[] args) {

        String text = """
                The quick brown fox jumps over the lazy dog.
                The quick fox is very quick indeed. The dog is not quick.""";

        // Normalize and split into words
        String[] words = text.toLowerCase().split("\\W+");
        List<String> wordList = List.of(words);

        // Count specific words
        System.out.println("Word frequencies:");
        System.out.println("the: " + Collections.frequency(wordList, "the"));
        System.out.println("quick: " + Collections.frequency(wordList, "quick"));
        System.out.println("fox: " + Collections.frequency(wordList, "fox"));
        System.out.println("dog: " + Collections.frequency(wordList, "dog"));
        System.out.println("lazy: " + Collections.frequency(wordList, "lazy"));

        // Find most frequent word
        String mostFrequent = wordList.stream()
                .distinct()
                .max(Comparator.comparingInt(a -> Collections.frequency(wordList, a)))
                .orElse("");

        System.out.println("\nMost frequent word: " + mostFrequent +
                " (" + Collections.frequency(wordList, mostFrequent) + " times)");
    }
}

此示例演示了 Collections.frequency 在文本分析中的实际应用。我们将文本字符串处理成单词,然后计算特定单词的出现次数。该示例还显示了查找最常用的单词。

代码首先规范化文本(转换为小写)并将其拆分为单词。然后,我们使用 frequency 计算特定单词并将其与流结合起来查找最常用的单词。这表明 frequency 可以成为更复杂文本处理的一部分。

来源

Java Collections.frequency 文档

在本教程中,我们深入探讨了 Java Collections.frequency 方法。我们涵盖了基本用法、计数自定义对象、不同的集合类型、处理 null 值、性能注意事项、嵌套集合以及一个实用的词频计数器应用程序。此方法对于有效地计算任何集合类型中的元素出现次数非常有用。

作者

我的名字是 Jan Bodnar,我是一位经验丰富的程序员,在这一领域拥有多年的经验。我于 2007 年开始撰写编程文章,此后撰写了 1,400 多篇文章和八本电子书。凭借八年以上的教学经验,我致力于分享我的知识并帮助其他人掌握编程概念。

列出所有Java教程