Zapytano mnie o to podczas wywiadu i nie jestem przekonany, że udzieliłem najlepszej odpowiedzi, jaką mogłem mieć. Wspomniałem, że możesz przeprowadzić wyszukiwanie równoległe i że wartości zerowe były obsługiwane w jakiś sposób, którego nie pamiętałem. Teraz zdaję sobie sprawę, że myślałem o Optionals. Czego tu brakuje? Twierdzą, że to lepszy lub bardziej zwięzły kod, ale nie jestem pewien, czy się zgadzam.
Biorąc pod uwagę, jak zwięźle udzielono na to odpowiedzi, wydaje się, że nie było to jednak zbyt szerokie pytanie.
Jeśli zadają to pytanie podczas wywiadów i oczywiście tak jest, czemu może służyć jego rozbicie, a nie utrudnianie znalezienia odpowiedzi? To znaczy, czego szukasz? Mogłabym rozbić pytanie i uzyskać odpowiedzi na wszystkie pytania podrzędne, ale potem utworzyć pytanie nadrzędne z linkami do wszystkich pytań podrzędnych ... wydaje się jednak dość głupie. Skoro już o tym mowa, proszę podać przykład mniej ogólnego pytania. Nie wiem, jak zadać tylko część tego pytania i nadal uzyskać sensowną odpowiedź. Mógłbym zadać dokładnie to samo pytanie w inny sposób. Na przykład mógłbym zapytać „Czemu służą strumienie?” lub „Kiedy powinienem używać strumienia zamiast pętli for?” lub „Po co przejmować się strumieniami zamiast pętli for?” Są to jednak dokładnie to samo pytanie.
... czy też jest uważany za zbyt szeroki, ponieważ ktoś udzielił naprawdę długiej, wielopunktowej odpowiedzi? Szczerze mówiąc, każdy wtajemniczony mógłby to zrobić z praktycznie każdym pytaniem. Jeśli na przykład jesteś jednym z autorów JVM, prawdopodobnie mógłbyś mówić o pętlach for przez cały dzień, podczas gdy większość z nas nie mogła.
„Zmień pytanie, aby ograniczyć je do konkretnego problemu, z dostateczną szczegółowością, aby znaleźć odpowiednią odpowiedź. Unikaj zadawania wielu odrębnych pytań naraz. Zobacz stronę Jak zadawać, aby uzyskać pomoc w wyjaśnieniu tego pytania”.
Jak zauważono poniżej, udzielono adekwatnej odpowiedzi, która dowodzi, że istnieje i jest wystarczająco łatwa do udzielenia.
źródło
Odpowiedzi:
Ciekawe, że pytanie w wywiadzie dotyczy zalet, bez pytania o wady, bo są i jedno.
Strumienie mają bardziej deklaratywny styl . Lub bardziej wyrazisty styl. Można uznać, że lepiej jest zadeklarować swój zamiar w kodzie, niż opisać, jak to się robi:
return people .filter( p -> p.age() < 19) .collect(toList());
... mówi dość wyraźnie, że filtrujesz pasujące elementy z listy, podczas gdy:
List<Person> filtered = new ArrayList<>(); for(Person p : people) { if(p.age() < 19) { filtered.add(p); } } return filtered;
Mówi „Robię pętlę”. Cel pętli tkwi głębiej w logice.
Strumienie są często bardziej zwięzłe . Ten sam przykład to pokazuje. Terser nie zawsze jest lepszy, ale jeśli potrafisz być jednocześnie zwięzły i ekspresyjny, tym lepiej.
Strumienie mają silne podobieństwo do funkcji . Java 8 wprowadza lambdy i interfejsy funkcjonalne, co otwiera cały zestaw zaawansowanych technik. Strumienie zapewniają najwygodniejszy i najbardziej naturalny sposób stosowania funkcji do sekwencji obiektów.
Strumienie zachęcają do mniejszej zmienności . Jest to w pewnym sensie związane z aspektem programowania funkcjonalnego - programy, które piszesz przy użyciu strumieni, są typem programów, w których nie modyfikujesz obiektów.
Strumienie zachęcają do luźniejszych sprzężeń . Twój kod obsługi strumienia nie musi znać źródła strumienia ani jego ostatecznej metody kończenia.
Strumienie mogą w zwięzły sposób wyrażać dość wyrafinowane zachowanie . Na przykład:
Na pierwszy rzut oka może wyglądać tak, jakby filtrował cały strumień, a następnie zwraca pierwszy element. Ale tak naprawdę
findFirst()
napędza całą operację, więc skutecznie zatrzymuje się po znalezieniu jednej pozycji.Strumienie umożliwiają przyszły wzrost wydajności . Niektórzy przeprowadzili testy porównawcze i stwierdzili, że strumienie jednowątkowe z pamięci
List
lub tablic w pamięci mogą być wolniejsze niż równoważna pętla. Jest to prawdopodobne, ponieważ w grze jest więcej obiektów i kosztów ogólnych.Ale strumienie się skalują. Oprócz wbudowanej obsługi Java dla operacji równoległych strumieni, istnieje kilka bibliotek do rozproszonej redukcji map przy użyciu strumieni jako API, ponieważ model pasuje.
Niedogodności?
Wydajność :
for
pętla przez tablicę jest niezwykle lekka zarówno pod względem wykorzystania sterty, jak i procesora. Jeśli priorytetem jest surowa prędkość i oszczędność pamięci, używanie strumienia jest gorsze.Znajomość . Świat jest pełen doświadczonych programistów proceduralnych z wielu środowisk językowych, którym pętle są znane, a strumienie są nowatorskie. W niektórych środowiskach chcesz napisać kod, który jest znany takiej osobie.
Narzut poznawczy . Ze względu na deklaratywną naturę i zwiększoną abstrakcję od tego, co dzieje się pod spodem, może być konieczne zbudowanie nowego modelu mentalnego określającego, jak kod odnosi się do wykonywania. W rzeczywistości musisz to zrobić tylko wtedy, gdy coś pójdzie nie tak lub jeśli musisz dogłębnie przeanalizować wydajność lub subtelne błędy. Kiedy to „po prostu działa”, po prostu działa.
Debugery są ulepszane, ale nawet teraz, gdy przechodzisz przez kod strumieniowy w debugerze, może to być trudniejsze do wykonania niż równoważna pętla, ponieważ prosta pętla jest bardzo blisko zmiennych i lokalizacji kodu, z którymi współpracuje tradycyjny debugger.
źródło
Pomijając zabawę składniową, strumienie są zaprojektowane do pracy z potencjalnie nieskończenie dużymi zbiorami danych, podczas gdy tablice, kolekcje i prawie każda klasa Java SE, która implementuje Iterowalność, są całkowicie w pamięci.
Wadą strumienia jest to, że filtry, mapowania itp. Nie mogą zgłaszać sprawdzonych wyjątków. To sprawia, że Stream jest złym wyborem dla, powiedzmy, pośrednich operacji we / wy.
źródło
Stream<Row>
- lub byłoby możliwe napisanie własnejStream
implementacji opakowującej operacje kursora wynikowego DB .Arrays.asList("test", null).stream().forEach(s -> System.out.println(s.length()));
Zrozumiałeś nieprawidłowo: operacje równoległe używają
Stream
s,Optional
a nie s.Możesz zdefiniować metody pracujące ze strumieniami: przyjmować je jako parametry, zwracać itp. Nie możesz zdefiniować metody, która przyjmuje pętlę jako parametr. Pozwala to na jednorazową skomplikowaną operację strumienia i wielokrotne korzystanie z niego. Zwróć uwagę, że Java ma tutaj wadę: twoje metody muszą być wywoływane w
someMethod(stream)
przeciwieństwie do własnych strumienistream.someMethod()
, więc mieszanie ich komplikuje czytanie: spróbuj zobaczyć kolejność operacji wWiele innych języków (C #, Kotlin, Scala itp.) Dopuszcza pewną formę „metod rozszerzających”.
Nawet jeśli potrzebujesz tylko operacji sekwencyjnych i nie chcesz ich ponownie używać, aby móc używać strumieni lub pętli, proste operacje na strumieniach mogą odpowiadać dość złożonym zmianom w pętlach.
źródło
Optional
jest alternatywą dlanull
, ale nie ma nic wspólnego z operacjami równoległymi. Chyba że „Teraz zdaję sobie sprawę, że myślałem o opcjach” w twoim pytaniu dotyczy tylkonull
obsługi?Pętla się nad sekwencją (tablica, kolekcja, dane wejściowe, ...), ponieważ chcesz zastosować jakąś funkcję do elementów sekwencji.
Strumienie dają możliwość komponowania funkcji na elementach sekwencji i pozwalają na implementację większości typowych funkcji (np. Mapowania, filtrowania, wyszukiwania, sortowania, zbierania, ...) niezależnie od konkretnego przypadku.
Dlatego biorąc pod uwagę pewne zadanie zapętlenia, w większości przypadków można to wyrazić za pomocą mniejszego kodu za pomocą strumieni, tj. Zyskujesz czytelność .
źródło
Powiedziałbym, że jego równoległość jest tak łatwa w użyciu. Spróbuj iterować ponad miliony wpisów równolegle z pętlą for. Idziemy do wielu procesorów, nie szybciej; więc im łatwiej jest biegać równolegle, tym lepiej, a przy
Stream
s to pestka.Bardzo podoba mi się ich gadatliwość . Zrozumienie tego, co faktycznie robią i produkują, zajmuje niewiele czasu, a nie tego, jak to robią.
źródło