Wat zijn in Java de voordelen van streams boven loops?

Dit werd mij gevraagd tijdens een interview en ik ben er niet van overtuigd dat ik het beste antwoord heb gegeven dat ik kon hebben. Ik zei dat je een parallelle zoekopdracht kunt uitvoeren en dat null-waarden werden afgehandeld op een manier die ik me niet kon herinneren. Nu realiseer ik me dat ik aan Optioneel dacht. Wat mis ik hier? Ze beweren dat het een betere of beknoptere code is, maar ik weet niet zeker of ik het ermee eens ben.


Gezien de beknoptheid van het antwoord, lijkt het erop dat dit toch geen al te brede vraag was.


Als ze deze vraag tijdens interviews stellen, en dat is duidelijk zo, welk doel zou het opsplitsen dan kunnen dienen, behalve dat het moeilijker wordt om een ​​antwoord te vinden? Ik bedoel, waar ben je naar op zoek? Ik zou de vraag kunnen opsplitsen en alle subvragen kunnen beantwoorden, maar dan een bovenliggende vraag kunnen maken met links naar alle subvragen… lijkt me echter nogal dwaas. Nu we toch bezig zijn, geef me een voorbeeld van een minder brede vraag. Ik ken geen manier om slechts een deel van deze vraag te stellen en toch een zinvol antwoord te krijgen. Ik zou precies dezelfde vraag op een andere manier kunnen stellen. Ik zou bijvoorbeeld kunnen vragen “Welk doel dienen streams?” of “Wanneer zou ik een stream gebruiken in plaats van een for-lus?” of “Waarom zou je je druk maken om streams in plaats van for-loops?” Dit zijn echter allemaal precies dezelfde vragen.

…of wordt het als te breed beschouwd omdat iemand een heel lang meerpuntsantwoord heeft gegeven? Eerlijk gezegd kan iedereen die het weet dat doen met vrijwel elke vraag. Als je bijvoorbeeld een van de auteurs van de JVM bent, zou je waarschijnlijk de hele dag over for-loops kunnen praten, terwijl de meesten van ons dat niet konden.

“Bewerk de vraag om deze te beperken tot een specifiek probleem met voldoende details om een ​​adequaat antwoord te kunnen geven. Stel niet meerdere afzonderlijke vragen tegelijk. Zie de Hoe te vragen-pagina voor hulp bij het verduidelijken van deze vraag.”

Zoals hieronder vermeld, is er een adequaat antwoord gegeven dat bewijst dat er een is en dat het eenvoudig genoeg is om te geven.


Antwoord 1, autoriteit 100%

Interessant dat de interviewvraag vraagt ​​naar de voordelen, zonder te vragen naar nadelen, want die zijn er allebei.

Stremen zijn een meer declaratieve stijl. Of een meer expressievestijl. Het kan als beter worden beschouwd om uw bedoeling in code te verklaren dan om hoehet te beschrijven:

return people
     .filter( p -> p.age() < 19)
     .collect(toList());

… zegt heel duidelijk dat je overeenkomende elementen uit een lijst filtert, terwijl:

List<Person> filtered = new ArrayList<>();
 for(Person p : people) {
     if(p.age() < 19) {
         filtered.add(p);
     }
 }
 return filtered;

Er staat: “Ik doe een lus”. Het doel van de lus ligt dieper in de logica begraven.

Streams zijn vaak terser. Hetzelfde voorbeeld toont dit aan. Terser is niet altijd beter, maar als je tegelijkertijd kort en expressief kunt zijn, des te beter.

Stremen hebben een sterke affiniteit met functies. Java 8 introduceert lambda’s en functionele interfaces, wat een hele speelgoeddoos van krachtige technieken opent. Streams bieden de handigste en meest natuurlijke manier om functies toe te passen op reeksen objecten.

Stremen stimuleren minder veranderlijkheid. Dit is een beetje gerelateerd aan het functionele programmeeraspect — het soort programma’s dat je schrijft met behulp van streams zijn meestal het soort programma’s waarin je geen objecten wijzigt.

Stremen stimuleren een lossere koppeling. Je streamverwerkingscode hoeft de bron van de stream of de uiteindelijke beëindigingsmethode niet te kennen.

Stremen kunnen heel gesofisticeerd gedrag op beknopte wijze uitdrukken. Bijvoorbeeld:

stream.filter(myfilter).findFirst();

Het lijkt op het eerste gezicht alsof het de hele stream filtert en vervolgens het eerste element retourneert. Maar in feite stuurt findFirst()de hele operatie aan, dus stopt het efficiënt na het vinden van één item.

Streams bieden ruimte voor toekomstige efficiëntiewinsten. Sommige mensen hebben gebenchmarkt en ontdekten dat single-threaded streams van in-memory Lists of arrays langzamer kunnen zijn dan de equivalente lus. Dit is aannemelijk omdat er meer objecten en overheads in het spel zijn.

Maar streams schalen. Naast Java’s ingebouwde ondersteuning voor parallelle stroombewerkingen, zijn er een paar bibliotheken voor gedistribueerde kaartverkleining met Streams als de API, omdat het model past.

Nadelen?

Prestaties: een forloop door een array is extreem licht, zowel wat betreft heap- als CPU-gebruik. Als pure snelheid en geheugenbesparing een prioriteit zijn, is het gebruik van een stream slechter.

Bekendheid. De wereld zit vol met ervaren procedurele programmeurs, met verschillende taalachtergronden, voor wie loops bekend zijn en streams nieuw. In sommige omgevingen wil je code schrijven die bekend is bij dat soort mensen.

Cognitieve overhead. Vanwege het declaratieve karakter en de toegenomen abstractie van wat eronder gebeurt, moet je misschien een nieuw mentaal model bouwen van hoe code zich verhoudt tot uitvoering. Eigenlijk hoef je dit alleen te doen als er iets misgaat, of als je de prestaties of subtiele bugs grondig moet analyseren. Als het “gewoon werkt”, werkt het gewoon.

Debuggersverbeteren, maar zelfs nu, wanneer je door de streamcode in een debugger stapt, kan het moeilijker zijn dan de equivalente lus, omdat een eenvoudige lus heel dicht bij de variabelen ligt en codelocaties waarmee een traditionele debugger werkt.


Antwoord 2, autoriteit 8%

Afgezien van syntactisch plezier, zijn Streams ontworpen om te werken met potentieel oneindig grote datasets, terwijl arrays, collecties en bijna elke Java SE-klasse die Iterable implementeert volledig in het geheugen zitten.

Een nadeel van een stream is dat filters, toewijzingen, enz. geen gecontroleerde uitzonderingen kunnen genereren. Dit maakt een Stream een ​​slechte keuze voor bijvoorbeeld intermediaire I/O-bewerkingen.


Antwoord 3, autoriteit 3%

  1. U realiseerde zich ten onrechte: parallelle bewerkingen gebruiken Streams, niet Optionals.

  2. Je kunt methoden definiëren die met streams werken: ze als parameters nemen, ze retourneren, enz. Je kunt geen methode definiëren die een lus als parameter neemt. Dit maakt een gecompliceerde streambewerking één keer mogelijk en kan deze vele malen worden gebruikt. Merk op dat Java hier een nadeel heeft: uw methoden moeten worden aangeroepen als someMethod(stream)in tegenstelling tot stream’s eigen stream.someMethod(), dus het mengen ervan bemoeilijkt het lezen: probeer de volgorde van bewerkingen te zien in

    myMethod2(myMethod(stream.transform(...)).filter(...))
    

    Veel andere talen (C#, Kotlin, Scala, enz.) staan ​​een of andere vorm van “extensiemethoden” toe.

  3. Zelfs als je alleen opeenvolgende bewerkingen nodig hebt en ze niet opnieuw wilt gebruiken, zodat je streams of loops kunt gebruiken, kunnen eenvoudige bewerkingen op streams overeenkomen met behoorlijk complexe veranderingen in de loops.


Antwoord 4, autoriteit 2%

Je loopt over een reeks (array, verzameling, invoer, …) omdat je een functie wilt toepassen op de elementen van de reeks.

Streams geven u de mogelijkheid om functies componerenop sequentie-elementen en maken het mogelijk om de meest voorkomende functies implementeren(bijv. in kaart brengen, filteren, zoeken, sorteren, verzamelen, … ) onafhankelijk van een concreet geval.

Daarom kun je bij een bepaalde lustaak in de meeste gevallen het met minder code uitdrukken met behulp van Streams, d.w.z. je krijgt leesbaarheid.


Antwoord 5, autoriteit 2%

Ik zou zeggen de parallelisatiedie zo gemakkelijk te gebruiken is. Probeer meer dan miljoenen items parallel te herhalen met een for-lus. We gaan naar veel cpu’s, niet sneller; dus hoe gemakkelijker het is om parallel te werken, hoe beter, en met Streams is dit een fluitje van een cent.

Wat ik erg leuk vind, is de breedsprakigheiddie ze bieden. Het kost weinig tijd om te begrijpen wat ze eigenlijk doen en produceren, in tegenstelling tot hoeze het doen.

Other episodes