Lambda in älterer JVM

Mal eine allgemeine Frage aus Interesse, vielleicht weiß das wer, aber warum funktionieren Lambdas eigentlich nicht in älteren JVMs?
Kann man die nicht in der IDE oder mit dem Compiler einfach simulieren?

IntelliJ macht z.B. automatisch das hier:

map.forEach( new Consumer<Value>() {
     @Override
     public void consume( Value v ) {
          v.doStuff();
     
});

wird (nur visuell) zu

map.forEach( (v) -> { v.doStuff(); } );

Ich sitze hier nur gerade vor einem Haufen Code der für Java 7 fit gemacht werden soll, aber jetzt werden mir alle Lambda Expressions rot angekreidet. Da frag ich mich warum das oben nicht auch anders herum geht…

Moin,
weil es die IMHO erst seit Java8 gibt !
VG Klaus

Was so auch erstmal gut ist. Es ist eines, das als Lambda darzustellen - aber was anderes es auch tatsächlich umzuschreiben. Jetzt überleg dir mal das wäre so, dann würdest du dir Abhängigkeiten zu IDE oder Compiler schaffen, die du nicht haben möchtest.

IDE: damit zwingst du alle deine Kollegen, dass Ihr die gleiche verwenden müsst (oder halt unterstütze). Wir haben hier so ein Projekt, welches auf Ecilpse zugeschnitten wurde. Wir haben dafür extra ein Batch-Script geschrieben, was das Projekt umbiegt, sodass wir es auch mit Intellij verwenden können.

Compiler: Am besten noch einen exotischen verwenden, der nicht auf allen Plattformen verfügbar ist (wäre auch bei uns toll, da hier windows/mac und linux eingesetzt wird).

Setzt Ihr maven ein? Hab jetzt nicht geschaut, aber vielleicht gibt es dafür ein Plugin. Damit würdest du Abhängigkeiten umgehen.
Wahrscheinlich eher unwahrscheinlich aber: eine alternative könnte auch eine andere Sprache sein. Z.B. Kotlin (damit wärt ihr afair sogar bis 1.6 abwärtskompatibel)

Java 8 Lambda schreiben, compilieren und den Bytecode mit Retrolambda auf Java 7 lauffähig machen.

Aber Java 7 ist doch eigentlich eh schon EOL?

Die Frage bezieht sich explizit auf die JVM. Die Antworten zielen bisher vorranging auf den Compiler oder die IDE. Beides sollte unabhängig voneinander betrachtbar sein: Der bytecode, den die JVM “ausführt”, ist ja unabhängig von dem source code, aus dem er erzeugt wurde. (Ja, “unabhängig” … ihr wißt schon ;-)).

Grundsätzlich sollte es IMHO kein Problem sein, sowas wie

javac -source 1.8 -target 1.7 SomethingWithLambda

zu compilieren und auf einer 7er JVM auszuführen. (Natürlich nur, solange die Klasse nicht Klassen von Java 8 verwendet, wie etwa das java.util.functional package).

Ausprobiert habe ich es (noch) nicht, werde das aber ggf. mal aus Neugier. Der Bytecode für die beiden Schnipsel aus dem Eröffnungsbeitrag sollte praktisch gleich sein, genau wie für das noch concisere

map.forEach(Value::doStuff);

Es gibt noch den caveat invokevirtual - spielt das eine Rolle? Da bin ich nicht sicher…

Retrolambda ist nur die halbe Lösung, man muss natürlich alle Klassen ausbauen oder mitliefern, die es erst seit Java 8 gibt (z.B. Function)

Darauf bezog sich das

oben. Aber wenn man diese Klassen nicht verwendet, sondern es nur darum geht das sprachliche Konstrukt eines Lambdas zu verwenden, dann sollte es IMHO mit source und target zu schaffen sein. (Müßte mal eine alte VM installieren, um es zu testen…)

Richtig, selbst Oracles Java 8 ist kurz vor dem OEL, warum man da noch nach Java 7 portiert verstehe ich ehrlich gesagt nicht, ausser das Projekt wurde vor Jahren geplant und nun haelt man sich strikt an den Plan und ignoriert die Realtitaet. Ein anderer Grund kann sein dass man auf propritaerer Plattformen festsitzt (SAP?), aber ich kann hier auch nur raten :wink:

Weil das Tochterunternehmen, wegen der vielen Sicherheitslücken, Java verboten hat.
Deswegen hat man seit Java 6 keine neueren Versionen mehr installiert, sondern setzt komplett auf andere Sprachen.
Hört sich widersprüchlich an, auf bürokratischer Ebene trotzdem schwer anfechtbar.

Und wie @Marco13 bereits sagte, es gibt einen Unterschied zwischen dargestellten Code, realen Sourcecode, byte Code und ausgeführten Code.
Wenn ich mich recht entsinne waren Lambdas in den Anfangswochen von Java 8 auch nur mit dynamisch erzeugten inneren Klassen emuliert.
Was sehr zur Ernüchterung vieler beigetragen hatte, was die Performance anging.

Im Grunde hätte Oracle in den J8 Compiler doch einfach nur die Möglichkeit einbauen können, bei Java 7 und kleinerem JVM target, die Lambdas wieder mit inneren Klassen auf byte-code Ebene zu emulieren.

Ich schätze aber mal das EOL Prinzip ist ein gutes Argument. Man möchte wohl nicht alte JVMs unterstützen.

Es ist nicht ganz klar, was „fit machen“ heißt. Wenn das komplett auf Java 8 setzt (und eben auch die Java8-Klassen verwendet) könnte das schwierig werden. (Obwohl ich in der Übergangsphase in der umgekehrten Richtung schonmal lokale Klassen für Function, Predicate & Co erstellt hatte, um die schon verwenden zu können, und nach dem Update auf 8 einfach mit „Organize Imports“ glattbügeln konnte :smiley: )

Andernfalls könnte sowas wie

javac -source 1.8 -target 1.7 SomethingWithLambda

ja vielleicht funktionieren…?