最高の回答はJava 8に対する絶対的な最良の回答ですが、同時にパフォーマンスの面で絶対的に最悪です。パフォーマンスの悪いアプリケーションが本当に必要な場合は、先に進んでそれを使用してください。個人名の一意のセットを抽出するという単純な要件は、単なる「For-Each」と「セット」によって達成されるものとします。リストのサイズが10を超えると、事態はさらに悪化します。
次のように、20個のオブジェクトのコレクションがあるとします。
public static final List<SimpleEvent> testList = Arrays.asList(
new SimpleEvent("Tom"), new SimpleEvent("Dick"),new SimpleEvent("Harry"),new SimpleEvent("Tom"),
new SimpleEvent("Dick"),new SimpleEvent("Huckle"),new SimpleEvent("Berry"),new SimpleEvent("Tom"),
new SimpleEvent("Dick"),new SimpleEvent("Moses"),new SimpleEvent("Chiku"),new SimpleEvent("Cherry"),
new SimpleEvent("Roses"),new SimpleEvent("Moses"),new SimpleEvent("Chiku"),new SimpleEvent("gotya"),
new SimpleEvent("Gotye"),new SimpleEvent("Nibble"),new SimpleEvent("Berry"),new SimpleEvent("Jibble"));
オブジェクトの場所はSimpleEvent
次のようになります。
public class SimpleEvent {
private String name;
private String type;
public SimpleEvent(String name) {
this.name = name;
this.type = "type_"+name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
テストするには、次のようなJMHコードを使用します(承認された回答で言及されているのと同じ別個の ByKey述語を使用していることに注意してください)
@Benchmark
@OutputTimeUnit(TimeUnit.SECONDS)
public void aStreamBasedUniqueSet(Blackhole blackhole) throws Exception{
Set<String> uniqueNames = testList
.stream()
.filter(distinctByKey(SimpleEvent::getName))
.map(SimpleEvent::getName)
.collect(Collectors.toSet());
blackhole.consume(uniqueNames);
}
@Benchmark
@OutputTimeUnit(TimeUnit.SECONDS)
public void aForEachBasedUniqueSet(Blackhole blackhole) throws Exception{
Set<String> uniqueNames = new HashSet<>();
for (SimpleEvent event : testList) {
uniqueNames.add(event.getName());
}
blackhole.consume(uniqueNames);
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(MyBenchmark.class.getSimpleName())
.forks(1)
.mode(Mode.Throughput)
.warmupBatchSize(3)
.warmupIterations(3)
.measurementIterations(3)
.build();
new Runner(opt).run();
}
次に、次のようなベンチマーク結果が得られます。
Benchmark Mode Samples Score Score error Units
c.s.MyBenchmark.aForEachBasedUniqueSet thrpt 3 2635199.952 1663320.718 ops/s
c.s.MyBenchmark.aStreamBasedUniqueSet thrpt 3 729134.695 895825.697 ops/s
ご覧のとおり、単純なFor-Eachは、Java 8 Streamと比較して、スループットが3倍、エラースコアが低くなっています。
より高いスループット、より良いパフォーマンス
Function<? super T, ?>
であるべきではないと思いFunction<? super T, Object>
ます。また、順序付けされた並列ストリームの場合、このソリューションは(normalとは異なりdistinct()
)どのオブジェクトが抽出されるかを保証しないことに注意してください。また、シーケンシャルストリームの場合、CHMを使用するとオーバーヘッドが追加されます(@nosidソリューションにはありません)。最後に、このソリューションfilter
は、JavaDocで述べられているように、述語がステートレスでなければならないメソッドの規約に違反しています。それでも賛成票を投じた。