我有一个数组列表,一个Java的集合类,如下所示:

ArrayList<String> animals = new ArrayList<String>();
animals.add("bat");
animals.add("owl");
animals.add("bat");
animals.add("bat");

如您所见,animals数组列表由3个bat元素和1个owl元素组成。我想知道在Collection框架中是否有返回蝙蝠出现次数的API,或者是否有另一种方法来确定出现次数。

我发现谷歌的集合Multiset确实有一个API,返回一个元素的总出现次数。但是这只与JDK 1.5兼容。我们的产品目前是JDK 1.6,所以我不能使用它。


当前回答

这说明了为什么像《Effective Java》一书中描述的那样“通过接口引用对象”是很重要的。

如果你对实现进行编码,并在代码中的50个地方使用ArrayList,当你找到一个好的“List”实现来计数项目时,你将不得不改变所有这50个地方,可能你将不得不破坏你的代码(如果它只被你使用,这不是一个大问题,但如果它被其他人使用,你也会破坏他们的代码)

通过对接口编程,您可以让这50个位置保持不变,并将实现从ArrayList替换为“CountItemsList”(例如)或其他一些类。

下面是一个关于如何编写这些代码的非常基本的示例。这只是一个样品,一个生产就绪的清单将更加复杂。

import java.util.*;

public class CountItemsList<E> extends ArrayList<E> { 

    // This is private. It is not visible from outside.
    private Map<E,Integer> count = new HashMap<E,Integer>();

    // There are several entry points to this class
    // this is just to show one of them.
    public boolean add( E element  ) { 
        if( !count.containsKey( element ) ){
            count.put( element, 1 );
        } else { 
            count.put( element, count.get( element ) + 1 );
        }
        return super.add( element );
    }

    // This method belongs to CountItemList interface ( or class ) 
    // to used you have to cast.
    public int getCount( E element ) { 
        if( ! count.containsKey( element ) ) {
            return 0;
        }
        return count.get( element );
    }

    public static void main( String [] args ) { 
        List<String> animals = new CountItemsList<String>();
        animals.add("bat");
        animals.add("owl");
        animals.add("bat");
        animals.add("bat");

        System.out.println( (( CountItemsList<String> )animals).getCount( "bat" ));
    }
}

这里应用的OO原则:继承、多态、抽象、封装。

其他回答

我想知道,为什么你不能在JDK 1.6中使用谷歌的Collection API。上面这么说吗?我认为可以,不应该有任何兼容性问题,因为它是为较低版本构建的。如果它是为1.6构建的,而你运行的是1.5,情况就会有所不同。

我哪里说错了吗?

所以用传统的方法自己卷吧:

Map<String, Integer> instances = new HashMap<String, Integer>();

void add(String name) {
     Integer value = instances.get(name);
     if (value == null) {
        value = new Integer(0);
        instances.put(name, value);
     }
     instances.put(name, value++);
}

我很确定集合中的静态频率方法在这里会派上用场:

int occurrences = Collections.frequency(animals, "bat");

反正我也会这么做。我很确定这就是jdk 1.6。

使用Streams的Java 8解决方案:

long count = animals.stream().filter(animal -> "bat".equals(animal)).count();
List<String> list = Arrays.asList("as", "asda", "asd", "urff", "dfkjds", "hfad", "asd", "qadasd", "as", "asda",
        "asd", "urff", "dfkjds", "hfad", "asd", "qadasd" + "as", "asda", "asd", "urff", "dfkjds", "hfad", "asd",
        "qadasd", "as", "asda", "asd", "urff", "dfkjds", "hfad", "asd", "qadasd");

方法1:

Set<String> set = new LinkedHashSet<>();
set.addAll(list);

for (String s : set) {

    System.out.println(s + " : " + Collections.frequency(list, s));
}

方法2:

int count = 1;
Map<String, Integer> map = new HashMap<>();
Set<String> set1 = new LinkedHashSet<>();
for (String s : list) {
    if (!set1.add(s)) {
        count = map.get(s) + 1;
    }
    map.put(s, count);
    count = 1;

}
System.out.println(map);