Използва ли последователен поток в Java 8 параметъра за комбиниране при извикване на collect?

Ако извикам collect на последователен поток (напр. от извикване на Collection.stream()), тогава ще използва ли параметъра на комбиниране, който подавам, за събиране? Предполагам, че не, но не виждам нищо в документацията. Ако съм прав, тогава изглежда жалко да трябва да доставям нещо, което знам, че няма да се използва (ако знам, че е последователен поток).


person Graeme Moss    schedule 13.06.2014    source източник
comment
Какво се случва, когато подадете null за комбинатора? Какво заключавате от този експеримент?   -  person JB Nizet    schedule 13.06.2014
comment
@JBNizet Ще хвърли NullPointerException.   -  person johnlinp    schedule 27.05.2020


Отговори (1)


Имайте предвид, че разработвате спрямо спецификациите на интерфейса -- не срещу изпълнението. Изпълнението може да се промени със следващата версия на Java, докато спецификацията трябва да остане стабилна.

Спецификацията не прави разлика между последователни и паралелни потоци. Поради тази причина трябва да приемете, че може да се използва комбинатор. Всъщност има добри примери, показващи, че комбинаторите за последователни потоци могат да подобрят производителността. Например следната операция намаляване свързва списък от низове. Изпълнението на кода без комбинатор има квадратична сложност. Интелигентното изпълнение с комбинатор може да намали времето за изпълнение с величини.

List<String> tokens = ...;
String result = tokens.stream().reduce("", String::concat, String::concat);
person nosid    schedule 13.06.2014
comment
Би било много умно, ако внедряването на Stream разпознае дали използването на комбинатора може да подобри производителността. По-големият риск обаче е самият разработчик да промени потока на паралелен в момент, когато е забравил за пропуснатия комбинатор... - person Holger; 13.06.2014
comment
@Holger Точно така, или друг разработчик предава поток към вашия код и този поток може да се промени, за да бъде паралелен в бъдеще. - person Stuart Marks; 13.06.2014
comment
Благодаря за вашият отговор. Имах същия проблем и въпреки че винаги се придържам към разработването срещу интерфейса, намирам за жалко, че няма проста версия на колектор без комбинатор. Това би направило нещата МНОГО по-лесни. Те можеха да направят Collector.Characteristics, за да укажат това, или по-проста версия на интерфейса Collector... - person glglgl; 03.09.2014
comment
Още един въпрос: Ето аз намери изречението A sequential implementation of a reduction using a collector would create a single result container using the supplier function, and invoke the accumulator function once for each input element. Това вече не показва ли, че комбинаторът не се използва в тази ситуация? - person glglgl; 03.09.2014
comment
@Holger, @ nosid Не разбрах съвсем как комбинаторът, който споменахте в примера, ще подобри производителността в последователен поток. Според моето разбиране във всеки един момент има акумулиращ низ и елемент в потока. Просто ги свързваме и създаваме нов акумулиращ низ. Изпускам ли нещо? - person GeekFactory; 21.11.2019
comment
@GeekFactory пренебрегвате разходите за „просто ги свържете“. Конкатенацията на низове предполага създаване на нов низ, който е копие на двата аргументни низа. Колкото по-дълъг е низът, толкова повече са режийните. И междинният резултат от множество конкатенации на низове е низ, който става все по-дълъг и по-дълъг. Можете да потърсите „Алгоритъмът на художника Шлемиел“ за интуитивна картина. Вижте също ideone.com/0kRRnt Само за да стане ясно, collect(joining()) все още е още по-добър, но се надявам, че виждате , използването на комбинатора намалява режийните разходи в този пример. - person Holger; 21.11.2019
comment
@Holger Уау! Това е чудесен пример за демонстрация на това как комбинаторът има смисъл в последователни потоци. Ако не греша return reduce.apply(......) работи като комбинатор, нали? Освен това има ли име за този алгоритъм, който използвате? - person GeekFactory; 21.11.2019
comment
@GeekFactory точно в този момент функцията действа като комбинатор. Това е еквивалентно на това, което прави Stream API, когато разделя работното натоварване за паралелни потоци. Когато става въпрос за име, бих казал, че е вариант на Разделяй-и- Победи. - person Holger; 21.11.2019
comment
Бихте ли предоставили, моля, подробен анализ или примери, показващи как това подобрява производителността? Или връзки към статии/изследвания? - person Vyacheslav Babanin; 28.03.2021