Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Schreib mal auf wie du es ohne Lambda-Expressions lösen würdest, dann helf ich dir mal!
Jetzt ganz vorsichtig: Lambda ist auf jedenfall kein Mist! Wenn man sich damit beschäftigt, dann erkennt man, dass vieles im API-Bereich und auch bei Collectionverarbeitung vereinfacht wird.
Beispiel eine Runnable einem Thread übergeben:
Vorher:
Java:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(System.nanoTime());
}
});
Nachher:
Java:
new Thread(() -> System.out.println(System.nanoTime()));
Ich würde gerne die Diskussion zu diesem Thema mal anheizen:
@Flown : ich finde die erste Version leserlicher denn ich verstehe dort ohne lange Tutorials wälzen zu müssen was gemacht wird. Die zweite Version ist zwar elegant zu lesen aber ich erkenne nicht was gemacht wird. Ich habe übrigens auch bei dem Code des TE nicht verstanden was da eigentlich gemacht wird. Aber vielleicht ist das auch nur mein Problem weil ich mich mit diesen Lambdas nicht anfreunden kann. Mich würde interessieren wie andere das sehen ? Bei den Fragen hier im Forum taucht das Thema jedenfalls nur vereinzelt auf. Daraus würde ich schliessen dass das selten benutzt wird.
Ich sehe das genau wie du JStein52. Diese () -> Variante ist einfach nur cryptisch. Für mich persönlich ist das kein gültiger Java Syntax. Will heißen: Man muss schon ganz genau wissen was das bewirken soll. Die zweite Variante kann man jedem Programmierer zeigen(Anfänger und Profi) und der weiß gleich was erzeugt wird und wem es übergeben wird.
Das ist im übrigen auch der Fall wenn man sich an die gängigen Java Koventionen hält. Es ist direkt zu sehen was eine Klasse ist, was ein statischer Methodenaufruf ist etc. Diese neuen "Features" á la: "->" oder "auch::toll" machen ansonsten leicht verständlichen Code unleserlich. Es sei denn natürlich man opfert seine Zeit und ließt sich gründlich! in die Materie ein.
Ich sehe darin aber keinen Vorteil. Der Code wird ein paar Zeilen kürzer. Ja. Aber auch wesentlich unleserlicher/unverständlicher.
Jaaa. Ich habe bis jetzt nicht verstanden was der TE da oben mit dem Code eigentlich machen will. Und auch @Flown hat das nicht wirklich oder 🙂🙂 sonst hätte er nicht danach gefragt was er machen will.
Genau. Wenn ich weiss was das soll dann verstehe ich es auch. Wahrscheinlich schreibe ich dann ein paar Zeilen Kommentar dazu damit andere es beim nächsten Lesen auch verstehen dann kann ich es auch gleich "gescheit" schreiben.
Also der outcome dieser Methode wäre interessant gewesen - was in der forEach passieren würde. Denn wenn zu der currentMeasure-Map irgendetwas hinzugefügt werden sollte, in der forEach, dann ist dieser Aufbau in Java 8 einfach falsch. Es wurden dafür Collector eingeführt, der Stream zu einer Collection(List, Set, Map, ...) zusammenfasst.
Dann würde der Code eher so aussehen:
Allgemein muss ich hier allen widersprechen, wenn es um Lambda-Expressions geht.
Es ist eine super Neuerung in Java und ich finde schon lange überfällig. Viele Sprachen haben Lambda-Expressions schon integriert, da sie für Verabeitung von Collections/Arrays (generell Datenmengen) einfach perfekt geeignet sind.
Beispiel:
Java:
// Pre Java 8
public int[] getEvenNumbers(int[] arr) {
int[] result = new int[arr.length];
int pos = 0;
for(int i : arr) {
if(i % 2 == 0) {
result[pos++] = i;
}
}
return Arrays.copyOf(result, pos);
}
Mit Java 8 kann man das ganz einfach mit Streams lösen (die man auch einfach automatisch parallelisieren kann):
Java:
public int[] getEvenNumbers(int[] arr) {
return Arrays.stream(arr)./*parallel().*/filter(i -> i % 2 == 0).toArray();
}
Wenn man jetzt diesen Ausdruck von links nach rechts liest, kann man schnell und intuitiv den Sinn dieser Methoden sehen.
Der wichtigste Vorteil von Lambda-Expressions & Streams ist und bleibt die Einführung von Lazyness in Java. Aber das ist erst interessant, wenn man sich damit auseinandergesetzt hat und man es auch wirklich braucht. Da es sich hier um ein Anfängerforum handelt, wird sich hier auch niemand so schnell mit Lambda-Expressions etc. auseinander setzen.
Ich persönlich finde Lambda Expressions in Java auch noch sehr ungewohnt und schreib manches lieber erstmal mit normalen Schleifen etc.
Aber in C# finde ich sie einfach praktisch und auch leicht einzusetzen. Warum? Dort gibt es sie schon länger und ich hab sie damals gleich mitgelernt.
In Java gabs es diese damals noch nicht und natürlich müssen viele erst lernen wie sie einzusetzen sind. Jüngere Programmierer welche damit "aufwachsen" haben es da natürlich einfacher.
Ich sehe trotzdem keinen Grund sowas jemals einzusetzen. Es ist eben nicht intuitiv. Oh, ein Arrays.stream(arr)... ja was kommt wohl da zurück? Und auf das, was ich nicht weiss was es ist, wird dann filter() aufgerufen. Ja was macht das denn nun wieder? Einen Filter auf einzelne Objekte im Array... oder gar auf das Array selbst? Und was ist das überhaupt für ein Filter? Welche Methode wird da auf welchem Objekt ausgeführt?
Es wird einfach viel zu viel an Code versteckt. Bei den Collectors genauso. Und das ist nicht nur von Nachteil für Programmierer, die sich nicht damit auskennen. Kommt es zu Bugs o.ä. kann erstmal gesucht werden warum die Map falsche Werte beinhaltet. Es kann nicht "rein- gedubuggt" werden, da es nirgens ein map.put() mehr gibt.
Ich sehe trotzdem keinen Grund sowas jemals einzusetzen. Es ist eben nicht intuitiv. Oh, ein Arrays.stream(arr)... ja was kommt wohl da zurück? Und auf das, was ich nicht weiss was es ist, wird dann filter() aufgerufen. Ja was macht das denn nun wieder? Einen Filter auf einzelne Objekte im Array... oder gar auf das Array selbst? Und was ist das überhaupt für ein Filter? Welche Methode wird da auf welchem Objekt ausgeführt?
@X5-599 Sei jetzt als Entwickler ganz ehrlich: Das meinst du nicht ernst.
Analoges Beispiel für einen der noch nie programmiert hat:
Java:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!);
}
}
Soll ich jetzt wirklich anfangen hier zu fragen was was soll? Jemand der noch nie einen Code im Leben gesehen hat, wird mit diesem Snippet nichts anfangen können (Was ist "public", "class", "static", "String", "[]", ...).
Jedoch wenn man schon ein wenig Ahnung vom Programmieren hat, dann kann man auch schon ein wenig Dokumentation/Tutorials lesen/anschauen.
Was bedeutet Arrays.stream(arr)? Einfach mal die Dokumentation lesen? HIER
Was ist übehaupt ein Stream? Auch in der Doku nachlesen: HIER
Was macht ein filter oder Stream im Allgemeinen? Oracle Tutorial
Alles einfach zum nachlesen. Die Oracle Tutorials sind einfach Klasse und fassen alles recht hübsch zusammen.
Also wenn ma sich etwas Zeit nimmt, so wie auch beim Lernen vom Programmieren, sollte sowas kein Thema sein. Sonst nenn ich sowas "Angst" vorm Weiterentwickeln.
Nein, bestimmt nicht. Ich habe das Thema hier zum Anlass genommen mich auch in anderen Foren mal zum dem Thema umzusehen, habe mir diverse Blogs und Tutorials reingezogen. Aber ich muss sagen, ich sehe das noch genauso wie @XS-599 ... Und dein Hello-World-Vergleich hinkt aber ein bisschen 😉😉 Erklär doch mal was der TE da ganz oben macht ??!!
@Flown
Und ob ich das ernst meine. Und wir reden hier ja nicht über Leute die keine Programmierer sind sondern über Profis und Anfänger. Mit Anfänger meine ich Leute, die wenigstens die Syntax von Java und dessen allgemeine Konventionen kennen. Ein jeder in diesen beiden Gruppen weiss was bei:
Code:
Klasse.objekt.methode()
passiert; Es ist direkt im Code ersichtlich was eine Klasse was ein Objekt und was eine Metodenaufruf ist.
Klar könnte man sich einlesen. Aber wenn man solchen Code schreibt setzt man quasi vorraus, dass das jeder zu machen hat, der irgendwann mal darüber stolpert. Und es ist für mich einfach nicht ersichtlich, warum ich jemandem aufbürden sollte 3 Tutorials zu lesen (und zu verstehen) für eine Zeile Code, der sich selbst erklären würde, wenn ich ihn in vielleicht 5 Zeilen auf Konventionelle Weise schriebe.
Ach, und wegen dem "weiterentwickeln". Ich bin schon dagegen alles machen zu "müssen" nur weils gerade neu und hipp ist. Neue Sachen müssen bei mir einen gewissen Vorteil bringen. Nicht nur einfach "neu" sein.
@JStein52 ich wüde den TO ja gerne helfen, doch er hat keinen vollständigen Code gegeben, seine Absicht kenne ich auch nicht und raten liegt mir fern. Hatte bereits eine Lösung gegeben, wie es assehen sollte, aber egal.
@X5-599 Das erinnert mich an die Zeiten von Java 5, wie Generics eingefügt wurden und jeder hat sich dagegen gesträubt. Aber mit der Zeit ist man zum Schluss gekommen, dass das doch ziemlich genial ist und jetzt kann man nicht mehr ohne vorstellen.
Trotzdem gilt: Viele großen Programmiersprachen haben Konzepte (Lambda-Expression, Function Pointer, Lazyness, etc.) schon integriert und auch gezeigt, dass man dadurch auch Automatismen dem Compiler, bzw. der Sprache selbst überlassen kann (automatische Parallelisierung, etc.).
Wir diskutieren schon wieder über Geschmack und über das lässt sich bekanntlich nicht streiten. Ich kann nur von mir ausgehen und ich habe mit Java 1.4.2 angefangen (als OOP, davor Cobol, C, ASM, ...). Da war für mich Java 5 schon eine Erleichterung und jeder hat damals gemeckert, der "alte" Weg sei der Bessere und jetzt haben wir Target Typing/Autoinfering/etc.
Es ist ja nicht so, dass das ein neuer Syntactic Sugar ist, sondern ein universelles Konzept und da sollte man doch schon etwas offen sein und sich ein wenig damit beschäftigen.
Ich kenne weder die Klasse Group noch was Group::getMeasures() zurückliefert. Aber laut Kontext liefert die Methode eine Collection zurück, dann sollte das in Java 7 so aussehen:
Ich weiß nicht ich habe lange Zeit beruflich mit Scala zu tun gehabt und habe einfach kein Problem mit funktionaler Programmierung und higher-order functions und finde sie sind leichter zu lesen als verschachtelte Schleifen (again: Geschmack).
So jetzt muss ich auch nochmal was loswerden. Zunächst mal sollte man die beiden Themen Stream und Lambda getrennt betrachten. Die Stream-Bibliothek ist einfach erstmal eine weitere Klasse(n), in die man sich natürlich erstmal ein wenig reinlesen muss. Das ist aber ganz normal und gehört dazu, wenn man sich fremden Code anguckt. Wenn man z.b. bisher nur mit AWT gearbeitet hat, jetzt aber ein Projekt mit Swing vorgesetzt bekommt, kann man auch nicht sagen: "was ist das komisches neues, das will ich nicht lernen, schreib mal Code mit Dingen die ich kenne".
Ein großer Vorteil der Stream-Bibliothek, die bisher hier nicht erwähnt wurde, ist Parallelisierung. Sagen wir mal, wir haben eine Liste mit 1000 Objekten der Klasse MyClass, und wir wollen nun nur Objekte, die eine bestimmte Eigenschaft erfüllen (Methode in MyClass: hatEigenschaft()). Diese Methode braucht aber nun seeeehr lang, um die Eigenschaft zu prüfen. Erster Gedanke also, mehrere Threads die Eigenschaft von mehreren Objekten gleichzeitig prüfen lassen. Ohne Stream-Bibliothek muss man erstmal die Liste aufteilen, die Berechnung an Threads verteilen, und das Ergebnis wieder zusammen fügen. Vermutlich werden das ca. 100 Zeilen Code. Mit der Stream-Bibliothek und Java7-Syntax also ohne die bösen Lambdas:
Java:
liste = liste.stream().parallel()
.filter(new Predicate<MyClass>() {
public boolean test(MyClass obj) {
return obj.hatEigenschaft();
}
})
.collect(Collectors.toList());
Wenn man jetzt noch Lambdas benutzt bzw. den ::-Operator:
Java:
liste = liste.stream().parallel()
.filter(obj -> obj.hatEigenschaft())
.collect(Collectors.toList());
//... oder ...
liste = liste.stream().parallel()
.filter(MyClass::hatEigenschaft())
.collect(Collectors.toList());
Ich denke, die Vorteile der Stream-Bibliothek kann man nicht verneinen. Und man kann sie auch vollkommen ohne Lambdas benutzen. Lambdas sind nochmal eine kürzere Schreibweise, die man mögen kann oder auch nicht, wie Flown sagte, Geschmacksache. Aber gerade die Stream-Klasse profitiert nochmal erheblich von den Lambdas.
[...]
Ein großer Vorteil der Stream-Bibliothek, die bisher hier nicht erwähnt wurde, ist Parallelisierung. [...] Lambdas sind nochmal eine kürzere Schreibweise, [...]
Ob das ein Vorteil ist wird sich zeigen, bisher hört man eher Stimmen die sagen, mhm, ganz nette Idee aber hat seine Probleme. Die Probleme liegen in der unreflektierten Verwendung, erstens musst du garantieren das deine verwendeten "Funktionen" referentiell transparent sind und das zweite große Problem ist das ohne Zutun alles von einem Threadpool (dem globalen ForkJoin)-Pool abgearbeitet wird. Letzerer startet nur so viele Threads wie Prozessoren da sind und man kann sich mal schnell in einen Thread-Engpass befördern obwohl noch genug Systemressourcen da sind. Alles in allem wird derzeit eigentlich eher davon abgeraten .parallel() zu verwenden.
Und zum zweiten Punkt Lambdas sind KEINE kürzere Schreibweise es ist ein eigenes Konstrukt, ist ein Lambda z.B. kein Closure dann wird das in der umschließenden Klasse als statische Methode einkompiliert. Die Verarbeitung weicht also in vielen Bereichen von "inneren Klassen" ab.
Ok das mit der Parallelisierung hab ich tatsächlich nicht gewusst, vielen Dank. Zumindest kann man den Code irgendwann mit einem zusätzlichen ".parallel()" versehen, wenns vielleicht in späteren Versionen ausgereifter ist. Man muss zumindest nicht viel im Code ändern.
Stimmt zum Punkt Lambda, daran hatte ich gar nicht mehr gedacht. Das ist definitiv ein Argument FÜR Lambdas. Es wird keine zusätzliche anonyme Klasse benötigt, und es wird kein zusätzliches Objekt erstellt. Ich selbst benutze Lambdas zur Zeit gerne bei z.b. ActionListener. Ich denke jeder, der mit AWT oder Swing arbeitet, sollte solchen Code auch verstehen können:
Ich bin durchaus der Meinung, wenn man sie sparsam einsetzt, sind Lambdas lesbarer (oder zumindest nicht weniger lesbarer) und zudem (danke @nvidia) ressourcensparender 🙂
Also es kommt auf den Kontext der Lambdaexpression an, Brian Goetz hat einmal Lambda Under The Hood präsentiert und gezeigt, dass es im worst-case genau so "langsam" ist wie eine anonyme innere Klasse. Wie es jetzt ist, kann ich nicht sagen, da diese Präsentation vor Release von Java 8 passiert ist.
Also es kommt auf den Kontext der Lambdaexpression an, Brian Goetz hat einmal Lambda Under The Hood präsentiert und gezeigt, dass es im worst-case genau so "langsam" ist wie eine anonyme innere Klasse. Wie es jetzt ist, kann ich nicht sagen, da diese Präsentation vor Release von Java 8 passiert ist.
Ja, schrieb ich ja, wenn es KEIN Closure ist wird es als statische Funktion in den Bytecode geschrieben, im besten Fall wird es sogar gleich komplett inlined. Wenn der Lambdaausdruck ein Closure ist dann wird in aller Regel auch sowas wie eine innere Klasse draus, weil die Werte ja irgendwo gespeichert werden müssen. 🙂