Как усповно да добавим операция на стрийм на Java8?

+5 гласа
125 прегледа
попитан 2016 април 5 от Nikola.Nikolov. (3,100 точки)

Чудих се дали мога да добавя операция към стрийм, базиран на някакво условие заложено извън стрийма. Например, искам да се слага операция за лимит към стрийма си когато променливата limit е различна от -1.

Кодът ми в момента изглежда ето така, но тепърво трябва да видя други примери на стриймове, които да ползват кода по този начин, където обект от Stream е сложен към резултата на междинна операция,приложена на самия него си.

// Правим нещо

stream = stream.filter(e -> e.getTimestamp() < max);

// Лимитираме стрийма

if (limit != -1) {

   stream = stream.limit(limit);

}

// Collect-ваме стрийма към list

stream.collect(Collectors.toList());

Понеже променям стойностите на стрийма преди терминалната операция да е “извикана“, горе кода правилния начин за използване на Java 8 стриймове ли е?

1 отговор

0 гласа
отговорени 2016 април 6 от Daniel Ivanov (11,160 точки)

Като цяло няма смислова разлика между навързани извиквания и последователност от извиквания, съхраняващи средните връщащи стойности,следователно долните неща са 1 и също:

a = object.foo();
b = a.bar();
c = b.baz();

 и

c = object.foo().bar().baz();
В 2-та случая, всеки метод е извикан на резултата на предното извикване. Но накрая, междинните резултати не се запазват,а се губят в следващото извикване. В случая на stream API-то,междинните резултати не трябва да бъдат използвани след като си извикал следващия метод,следователно навързването е естествения начин за ползване на стрийм като безпроблемно се грижи да не извикаш повече от 1 метод на върната референция.
Въпреки това,не е грешно да съхраняваш референции към стриймове докато се придържаш към правилото да не връщаш повече от 1 референция. Както ти си го направил в случая - презаписваш променливата с резултата на следващото извикване,като така си гарантираш да не викаш повече от 1 метод на върната референция,следователно го ползваш като хората. Разбира се, това работи само с междинни резултати на 1 и същ тип, така че когато ползваш map или flatMap, вземайки на стрийм от различен тип референция, не можеш да презапишеш локалната променлива. След това трябва да внимаваш да не използваш пак старата променлива, но както казах,докато не я ползваш след следващото извикване, няма да имаш проблеми със съхраняването на междинните стойности.
Понякога ти трябва да я запазваш,например:
try(Stream<String> stream = Files.lines(Paths.get("myFile.txt"))) {
    stream.filter(s -> !s.isEmpty()).forEach(System.out::println);
}

Забележи,че кода е еквивалентен на следния:

try(Stream<String> stream = Files.lines(Paths.get("myFile.txt")).filter(s->!s.isEmpty())) {
    stream.forEach(System.out::println);
}

и

try(Stream<String> srcStream = Files.lines(Paths.get("myFile.txt"))) {
    Stream<String> tmp = srcStream.filter(s -> !s.isEmpty());
    tmp.forEach(System.out::println);
}

Те са еднакви,понеже forEach е винаги извикан в резултат на filter-а,който винаги е извикан на резултата на Files.lines и няма значение на кой резултат последната close() операция е извикана,понеже затварянето афектира целия стрийм.

С две думи го ползваш както трябва,даже аз бих предпочел да го направя по този начин.

Не е зле да отбележим,че другите начини също биха работили без проблеми,въпреки че не са смислово еднакви:

.limit(condition? aLimit: Long.MAX_VALUE)

предполага,че максималния брой елементи, с които можеш да се сблъскаш, е Long.MAX_VALUE,

но стриймовете могат да имат дори повече елементи, може даже и да са безкрай на брой.

.limit(condition? aLimit: list.size())

Когато stream source-а е list,тотално чупи оценката на стрийма. По принцип, непостоянен стрийм сорс може произволно да бъде променен до момента,в който терминалното действие е започнало.

Резултатът ще рефклектира всички модификации направени до момента. Когато добавиш междинна операция включваща list.size(), в случая истинския размер на списъка до момента, следващите модификации, направени на колецията м/у този момент и терминалната операция, могат да накарат тази стойност да има друг смисъл вместо предназначения смисъл на „без лимит“.

коментиран 2016 април 12 от Nikola.Nikolov. (3,100 точки)
Благодаря за отговора
...