Хоча відповідь з найбільш високою оцінкою - це абсолютно найкраща відповідь wrt 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- код, як це, (Зверніть увагу, я використовую той самий окремий предикат, який згадується у прийнятій відповіді):
@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-Every втричі кращий за пропускною здатністю і менший за показник помилок порівняно з Java 8 Stream.
Чим вища пропускна здатність, тим краще продуктивність
Function<? super T, ?>
, ніFunction<? super T, Object>
. Також слід зазначити, що для впорядкованого паралельного потоку це рішення не гарантує, який об’єкт буде вилучений (на відміну від звичайногоdistinct()
). Також для послідовних потоків є додаткові накладні витрати на використання CHM (який відсутній у розчині @nosid). Нарешті, це рішення порушує контрактfilter
методу, який предикат повинен бути без громадянства, як зазначено в JavaDoc. Тим не менш, підтримується.