Chociaż najwyższa pozytywna odpowiedź jest absolutnie najlepszą odpowiedzią w Javie 8, jest jednocześnie absolutnie najgorsza pod względem wydajności. Jeśli naprawdę chcesz mieć kiepską aplikację o niskiej wydajności, skorzystaj z niej. Prosty wymóg wyodrębnienia unikalnego zestawu Nazwisk Osób zostanie osiągnięty przez zwykłe „For-Each” i „Set”. Gorzej, jeśli lista jest powyżej 10.
Rozważ, że masz kolekcję 20 obiektów, takich jak to:
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"));
Twój obiekt SimpleEvent
wygląda następująco:
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;
}
}
Aby przetestować, masz taki kod JMH (Uwaga: używam tego samego odrębnego predykatuByKey wymienionego w zaakceptowanej odpowiedzi):
@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();
}
Następnie uzyskasz wyniki testu porównawczego :
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
I jak widać, prosty For-Each ma 3 razy lepszą przepustowość i mniejszy wynik błędu w porównaniu do Java 8 Stream.
Wyższa przepustowość, lepsza wydajność
Function<? super T, ?>
, nieFunction<? super T, Object>
. Należy również zauważyć, że dla uporządkowanego strumienia równoległego to rozwiązanie nie gwarantuje, który obiekt zostanie wyodrębniony (w przeciwieństwie do normalnegodistinct()
). Również w przypadku strumieni sekwencyjnych istnieje dodatkowy narzut związany z użyciem CHM (nieobecny w rozwiązaniu @nosid). Wreszcie, to rozwiązanie narusza umowęfilter
metody, której predykat musi być bezstanowy, jak podano w JavaDoc. Niemniej jednak głosowano.