Чи розумним є повернення потоків туди, куди ми зазвичай повертаємо колекції?


19

Під час розробки мого API, який не прив’язаний до жодного застарілого коду, я часто виявляю себе способами написання, які суто конвеєр потоків припиняється шляхом збору результатів. Як ця:

ImmutableSet<T> deriveSomethingMeaningfulFromPrivateState() {
    return myPrivateThingies.stream()
        .map(this::ownerOfThing)
        .map(Owner::socialStatus)
        .filter(SocialStatus::isHeAFineMatey)
        .collect(MyCustomCollectors.toImmutableSet());
}

Зараз більшості клієнтів цього класу зазвичай потрібна колекція (у цьому випадку ImmutableSet) для пошуку елементів та повторення над нею, але деякі клієнти можуть отримати користь від потоку, щоб вони могли виконувати ще деякі операції над цим Потік без необхідності отримувати новий потік із колекції. Тож повернення потоку дає клієнтам набір варіантів, які вони мали б, якби у них просто була колекція (зрештою, вони завжди можуть collect()передавати себе:

Stream<T> deriveSomethingMeaningfulFromPrivateState() {
    return myPrivateThingies.stream()
        .map(this::ownerOfthing)
        .map(Owner::socialStatus)
        .filter(SocialStatus::isHeAFineMatey);
        // No collect
}

Цей підхід для мене спокусливий спробувати, оскільки я не бачу жодних потенційних недоліків, які він міг би мати. Однак я жодного разу не бачив такого підходу в жодній бібліотеці (напевно, не було випущено багато бібліотек після появи Java 8), тому я трохи побоююся його застосувати. Існуючі бібліотечні класи зазвичай повертають колекції, коли вони отримують щось із приватного стану.

Чи може статися щось погане, якщо я вирішу повернути Потік, куди б мій власний попередній Java-8 повернув колекцію? Чи, мабуть, я роблю тут щось антипатрійне з усім тим, що походить від приватної держави?

Відповіді:


14

Якщо myPrivateThingiesвін змінений, ви створили приховану залежність між приватним станом та результатами потоку. Якщо клієнт може опосередковано викликати myPrivateThingiesзміну стану, тоді він отримає інший результат при виклику, collectніж той, який ви спочатку мали намір видавати.

Якщо myPrivateThingiesце незмінне, результат буде референтно прозорим, але є ще одна проблема, на яку потрібно стежити: семантичне сміття , тобто зберігання великої кількості пам'яті, яка більше не потрібна. ПрипустимоmyPrivateThingies , дуже великий і результат збору потоку невеликий. Клієнт може триматися за потік довго після того, як викинув усі посилання на об'єкт, який його виробляв, але streamце все ще не myPrivateThingiesперетворюється на збирання сміття. Швидке збирання результатів дозволило myPrivateThingiesб звільнитися.

Це насправді сталося до Java 7 під час дзвінка substring. Oracle вирішив, що потенційна економія ефективності від того, щоб не копіювати підрядку кожного разу, не варто періодично дивувати пересічного користувача надмірним споживанням пам'яті. Це не означає, що не було справжніх випадків використання для старої поведінки (наприклад, аналізаторів), але часто збирання результатів є охоче досить швидко, і коли це трапляється, у вас немає плюсів і потенційного хитрування.

З іншого боку, повернення потоку дає клієнтові можливість вибирати, яку структуру даних він хоче використовувати для проведення результатів, на відміну від вибору для нього. Можливо, варто запропонувати обидва варіанти.


4

Найважливіше, що потрібно врахувати: Streams можна повторити лише один раз, тоді як у вас є більше гнучкості щодо Collection: ви можете продовжувати створювати більше Streams або навітьIterator s, щоб робити додаткову, повторювану обробку результатів.

Отже, якщо ви не впевнені, чи збираються користувачі методу використовувати результати один раз і лише один раз, краще повернути a Collection.


У вашому зразковому коді є одна очевидна помилка: чому а SocialStatusмає поняття людини he,?


3

На мій погляд, ні. Те, що ви можете зробити з потоками, - це суворий набір речей, які ви можете зробити з колекціями, і часто вони можуть бути більш ефективними, тому немає причин не використовувати їх, крім незнайомства. "Виразки лямбда - це наркотик для шлюзу до Java 8, але Потоки - справжня залежність". (Venkat Subramaniam, функціональне програмування на Java )

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.