Хотя ответ с наибольшим количеством голосов является абсолютно лучшим по сравнению с Java 8, в то же время он является абсолютно худшим с точки зрения производительности. Если вы действительно хотите плохое приложение с низкой производительностью, тогда используйте его. Простое требование извлечения уникального набора личных имен должно быть достигнуто просто «для каждого» и «набором». Ситуация становится еще хуже, если список превышает 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 подобного кода (Пожалуйста , обратите внимание, им , используя тот же distinctByKey Predicate упоминается в общепринятом ответа):
@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 :
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 в 3 раза лучше по пропускной способности и меньше по количеству ошибок по сравнению с Java 8 Stream.
Чем выше пропускная способность, тем выше производительность
Function<? super T, ?>
, а неFunction<? super T, Object>
. Также следует отметить, что для упорядоченного параллельного потока это решение не гарантирует, какой объект будет извлечен (в отличие от обычногоdistinct()
). Также для последовательных потоков есть дополнительные издержки при использовании CHM (чего нет в решении @nosid). Наконец, это решение нарушает контрактfilter
метода, предикат которого должен быть без состояния, как указано в JavaDoc. Тем не менее проголосовал.