Warum Werttypen wichtig sind

Der neue ValueType in Java

Peter Verhas

©Shutterstock / JustDOne

Bisher kennt Java zwei verschiedene Datentypen: primitive Datentypen und Objekte. In den kommenden Releases wird es einen neuen Typ geben, den ValueType. Für die tägliche Programmierung sollte es keinen Unterschied zwischen Objekten und Werttypen geben, unter der Haube sind sie jedoch ziemlich unterschiedlich. ValueTypes sind wie Objekte, aber funktionieren wie primitive Datentypen. Das heißt, sie sind effektiv.

Andere Sprachen nutzen ebenfalls diese Art der Datenverarbeitung, obwohl sie sie normalerweise anders bezeichnen. In diesem Artikel beschreibe ich die Problematik von Objekten, die es notwendig macht, ValueTypes (oder Werttypen) in Java aufzunehmen. Anschließend erkläre ich, was ValueTypes sind, und gehe schließlich auf ihre Problematik ein. Ja, auch Werttypen unterliegen einer Problematik, und der Grund dafür ist ein sehr elementarer: Das Leben ist kein Ponyhof, und man kann nicht alles haben. Es gibt bei der Verwendung von ValueTypes gegenüber Objekten Vorteile, aber ebenso existieren Anwendungen beziehungsweise Programmierkonstrukte, bei denen Objekte besser passen. Im letzten Teil des Artikels erkläre ich außerdem, warum es Einschränkungen bei Werttypen gibt, wie z. B. keine Vererbung, Mangel an generischen Elementen und Unveränderlichkeit.

Objekte in Java

Objekte in Java sind kleine Speicherteile, die in der Regel in einem Segment des Speichers namens Heap gespeichert werden. Der Speicher wird beim Erstellen des Objekts zugewiesen und freigegeben, wenn das Objekt nicht mehr verwendet und „weggeräumt“ wird (Garbage Collection). Während der Lebensdauer des Objekts kann der Speicher, der das Objekt repräsentiert, im Verlauf des Garbage-Collection-Prozesses von einem Ort zum anderen verschoben werden. Auf diese Weise verwaltet Java den Speicher und stellt sicher, dass unabhängig davon, wie Objekte erstellt und zerstört werden, der Speicher nicht segmentiert wird. Andere Sprachen mit Garbage Collector, die den „Objektmüll“ zwar wegräumen, aber nicht komprimieren, laufen Gefahr, dass lange laufende Prozesse den Speicher segmentieren. Aber: Komprimieren ist ein CPU-intensiver Prozess, deshalb konkurriert Java GC kaum mit der Geschwindigkeit der Garbage Collection (GC) der Programmiersprache Go. Vor allem aber macht die Tatsache, dass sich die Objekte im Speicher bewegen, Zeiger nutzlos. Es wird zwar irgendwohin verwiesen, die Daten können sich jedoch nach einer Komprimierungsphase von GC bereits irgendwo anders befinden. Das ist der Grund, warum Java keine Zeiger verwendet – Java verwendet Referenzen.

Man könnte sich fragen, worin der Unterschied zwischen Zeiger und Referenz besteht. Kurz gesagt: Bei Referenzen handelt es sich um verwaltete Zeiger. Wenn GC ein Objekt im Speicher verschiebt, müssen alle Referenzen aktualisiert werden, damit sie jederzeit auf das richtige Objekt verweisen. Die Integration von nativem Code ist ebenfalls etwas umständlich. Java GC kann nicht wissen, wohin im durch den nativen Code verwalteten Speicher der Zeiger kopiert wurde. Außerdem gibt es in Java keine Zeigerarithmetik. Es existieren zwar Arrays, aber ansonsten kann man die schöne Zeigerarithmetik vergessen, an die man sich bei der Programmierung in C oder C++ vielleicht bereits gewöhnt hat. Der Vorteil ist, dass auch durch fehlerhafte Zeigerwertberechnungen verursachte Speicherfehler ausgeschlossen werden können.

Dennoch befinden sich die Objekte im Speicher, und wenn der Prozessor damit rechnen muss, muss das Objekt vom Hauptspeicher zum Prozessor gelangen. In den guten alten Zeiten, in denen die CPUs mit 4 MHz liefen, war das kein Problem. Die Geschwindigkeit des Speicherzugriffs war vergleichbar mit der Geschwindigkeit des Prozessors. Heute laufen Prozessoren mit 4 GHz, und der Speicherzugriff ist kaum schneller als früher. Die Technologie ist nicht schlecht, es handelt sich hierbei einfach um Physik. Man muss nur die Zeit berechnen, die benötigt wird, um von der CPU zum Speicher und mit Lichtgeschwindigkeit wieder zurück zu gelangen, das ist alles. Es gibt nur einen Weg, die Geschwindigkeit zu erhöhen, nämlich den Speicher näher an die Verarbeitungseinheit zu bringen. Und genau das ist es, was moderne CPUs auszeichnet: Sie verfügen über Speichercaches auf der CPU selbst. Leider ist nicht nur die CPU-Geschwindigkeit, sondern auch der Speicherbedarf gestiegen. Früher hatten wir 640 kB auf einem Computer, was für alle reichen musste. Heute hat mein Mac 16 GB. Und hier kommt wieder die Physik ins Spiel: Man kann nicht 16 GB oder mehr auf die CPU legen, da dort kein Platz ist und es auch keine effektive Methode gibt, das System entsprechend zu kühlen. Und wir wollen die CPU schließlich zum Rechnen nutzen, nicht zum Kochen.

W-JAX 2019 Java-Dossier für Software-Architekten

Kostenlos: Java-Dossier für Software-Architekten 2019

Auf über 30 Seiten vermitteln Experten praktisches Know-how zu den neuen Valuetypes in Java 12, dem Einsatz von Service Meshes in Microservices-Projekten, der erfolgreichen Einführung von DevOps-Praktiken im Unternehmen und der nachhaltigen JavaScript-Entwicklung mit Angular und dem WebComponents-Standard.

 

Wenn die CPU Speicherplatz braucht, wird im Cache gespeichert. Wenn ein Programm etwas von einem Speicherort abruft, ist es wahrscheinlich, dass es bald etwas vom anderen Speicherort abruft und so weiter. Deshalb liest die CPU ganze Speicherseiten in den Cache ein. Im Cache können sich viele Seiten aus verschiedenen Speicherbereichen befinden. Wenn wir auf ein Element in einem Array zugreifen wollen, kann das lange dauern (aus CPU-Sicht bedeutet „lange dauern“ ein paar Dutzend Nanosekunden), wenn wir jedoch ein zweites Element aus dem Array brauchen, befindet es sich bereits im Cache. Das ist sehr effektiv, es sei denn, es handelt sich um ein Array von Objekten. In diesem Fall ist das Array selbst ein zusammenhängender Bereich von Referenzen. Die CPU, die auf das zweite Element im Array zugreift, hat die Referenz im Cache, das Objekt selbst kann sich jedoch auf einer völlig anderen Seite befinden als auf der, auf der sich das erste Objekt befand. Es existieren einige Techniken zur Optimierung des Speicherlayouts, die dieses Problem teilweise lösen, aber der Knüller wäre es, wenn die Objekte im Speicher wie die Hühner auf der Stange aufgereiht gespeichert würden. Nur geht das leider nicht, denn selbst wenn sie nacheinander aufgereiht wären, wären sie durch den sogenannten Objektheader getrennt.

Der Objektheader befindet sich einige Bytes vor dem Objektspeicher, der das Objekt beschreibt. Er beinhaltet die Sperre, die in synchronisierten Anweisungen verwendet wird, und auch den Typ des Objekts. Wenn wir eine Referenz in einer Variable haben, die z. B. vom Typ Serializable ist, kennen wir den tatsächlichen Typ des Objekts nicht von der Variable selbst. Wir müssen uns Zugriff auf das Objekt verschaffen, damit die JRE den tatsächlichen Typ des Objekts lesen kann. In Java hilft dieser Objektheader bei Vererbung und Polymorphie. Auch betragen die wenigen Bytes in den 32-Bit-Implementierungen 12 Bytes und 16 Bytes auf der 64-Bit-Architektur. Das bedeutet, dass ein Integer einen 32-Bit-int-Wert und zusätzlich 128 Bit an administrativen Bits speichert – ein Verhältnis von 4:1.

ValueType

Werttypen versuchen, dieses Problem anzugehen. Ein ValueType ist insofern etwas wie eine Klasse, als er Felder und Methoden haben kann. ValueTypes werden im Rahmen des Valhalla-Projekts unter JEP 169 für Java entwickelt. Derzeit ist eine Early-Access-Version verfügbar. Diese Version ist ein Abkömmling der Version Java 11 und hat noch Einschränkungen. Die Syntax ist noch vorläufig (mit einigen Schlüsselwörtern, die mit einem doppelten Unterstrich beginnen und nicht in der endgültigen Version enthalten sein können), und auch einige Funktionen sind nicht implementiert. Dennoch gibt es die Möglichkeit, das Ganze auszuprobieren.

Der ValueType unterscheidet sich von einem Objekt dadurch, dass er keinen Objektheader und keine Identität hat, es keine Referenzen auf ihn gibt, Werttypen unveränderlich sind und es keine Vererbung zwischen Werttypen und somit auch keine Polymorphie gibt. Manches davon – wie das Fehlen eines Objektheaders – sind Implementierungsdetails, anderes wiederum Designentscheidungen. Kommen wir zu einigen Merkmalen von ValueTypes.

Keine Identität

ValueTypes haben keine Identität. Wenn wir es mit Objekten zu tun haben, können zwei davon identisch sein. Im Grunde genommen sprechen wir nur zweimal über das gleiche Objekt und Objekte können gleich sein. Im letztgenannten Fall haben wir zwei verschiedene Objekte – es handelt sich jedoch um Instanzen der gleichen Klasse, und die Methode equals() gibt true zurück, wenn wir sie vergleichen. Die Identität wird in Java mit dem Operator == überprüft, die Gleichheit, wie bereits erwähnt, mit der Methode equals().

Primitive Datentypen wie Byte, char, short, int, long, float, double oder boolean haben ebenfalls keine Identität. In diesem Fall ist das ziemlich offensichtlich. Es ist Unsinn, zu sagen, dass zwei Boolesche Werte beide true, aber dennoch unterschiedliche Instanzen sind. Als logische Werte haben auch Zahlen wie Null, Eins oder Pi keine Instanzen. Sie sind Werte. Wir können sie mit dem Operator == auf Gleichheit und nicht auf Identität prüfen. Die Idee der Werttypen ist es, den Satz dieser acht primitiven Werte um programmdefinierte Typen zu erweitern, die ebenfalls Werte darstellen.

Keine Referenzen

Die Werte werden in den Variablen und nicht im Heap gespeichert, und wenn die Bitdarstellung des Werts sich in einer Variable befindet, wird der Compiler den Typ erkennen. Ebenso erkennt er, dass die Bits in einer Variablen als 32-Bit-Ganzzahl mit Vorzeichen behandelt werden sollten, wenn die Variable vom Typ int ist. Es ist auch wichtig, zu beachten, dass, wenn ein ValueType als Argument an eine Methode übergeben wird, die Methode die „Kopie“ des ursprünglichen ValueTypes erhält. Das liegt daran, dass Java alle Argumente nach Wert und nie nach Referenz übergibt, was sich mit der Einführung von Werttypen auch nicht ändert. Wenn ein ValueType als Argument an einen Methodenaufruf übergeben wird, werden alle Bits des ValueTypes in die lokale beziehungsweise in die Argumentvariable der Methode kopiert.

Kein Objektheader

Da Werttypen Werte sind, die in den Variablen und nicht im Heap gespeichert werden, benötigen sie keinen Header. Der Compiler weiß einfach, was für ein Typ eine Variable ist und wie das Programm mit den Bits in dieser Variable umgehen soll. Das ist von entscheidender Bedeutung, wenn die ValueType-Arrays ins Spiel kommen. Genau wie bei primitiven Datentypen werden beim Erstellen eines Arrays mit einem Werttyp die Werte im Speicher nacheinander gepackt. Das bedeutet, dass wir bei ValueTypes nicht das Problem haben werden, das bei Objekt-Arrays auftritt. Es gibt keine Referenzen auf die einzelnen Elemente des Arrays, und sie können nicht im Speicher verteilt werden. Wenn die CPU das erste Element lädt, lädt sie alle Elemente, die sich auf der gleichen Speicherseite befinden. Der Zugriff auf nachfolgende Elemente nutzt den Vorteil des Prozessorcache.

Keine Vererbung

Es könnte eine Vererbung zwischen Werttypen geben, aber es wäre äußerst schwierig, sie durch den Compiler zu verwalten. Außerdem würde das Ganze nicht viele Vorteile bringen. Ich wage zu behaupten, dass das Zulassen von Vererbung nicht nur Probleme für den Compiler verursachen, sondern auch unerfahrene Programmierer dazu anregen würde, Konstrukte zu erstellen, die mehr Schaden als Nutzen brächten. In der kommenden Java-Version, die ValueTypes unterstützt, wird es keine Vererbung zwischen ValueTypes und auch nicht zwischen Klassen und ValueTypes geben. Dabei handelt es sich um eine Designentscheidung. Statt uns in vielen Erklärungen zu verlieren, betrachten wir einfach einige Beispiele.

Enthält eine Klasse C ein Feld vom Typ einer anderen Klasse P, enthält sie ebenfalls eine Referenz auf diese andere Klasse. Es kann auch sein, dass C der Klasse P untergeordnet ist. Das ist kein Problem. Beispielsweise gibt es eine verknüpfte Liste mit P-Instanzen. Es existiert ein Feld namens Next, das entweder „Null“ ist oder den Verweis auf das nächste P in der Liste enthält. Wenn die Liste auch Instanzen von C enthalten kann (zur Erinnerung: C erweitert P), dann hat C auch eine Referenz auf das nächste P. Die Liste kann C-Instanzen enthalten, da, wie die Vererbung impliziert, ein C auch ein P ist.

Wie sieht es aus, wenn P ein ValueType ist? Wir können die Elemente nicht miteinander verbinden. Es gibt keine Referenz auf das nächste P, da es keine Referenz auf einen ValueType gibt. Klassen können über Feldwerte gegenseitig aufeinander referenzieren. Werttypen implementieren nur Containment. Wenn ein ValueType ein Feld hat, das einem anderen ValueType entspricht, dann enthält er alle Bits dieses anderen ValueTypes. Ein Werttyp kann daher niemals ein Feld enthalten, das der Typ selbst ist. Denn das würde bedeuten, dass sich der Werttyp selbst enthält, was eine unendliche Rekursion in der Definition des Typs ist. Ein solcher Typ wäre unendlich groß, daher ist er in der Spezifikation ausdrücklich verboten. Wenn ValueTypes voneinander erben könnten, wäre die Einschränkung komplexer. In diesem Fall könnten wir nicht einfach sagen, dass sich ein ValueType nicht selbst enthalten darf. Es hätte jeder andere Werttyp verboten werden müssen, der vom aktuellen Werttyp abstammt.

Man muss versuchen, sich eine Variable vorzustellen, die vom Typ V ist. Eine solche Variable sollte groß genug sein, um alle Bits von V zu beinhalten, aber auch groß genug, um alle Bits von K aufzunehmen, wenn es möglich wäre, Wertobjekte zu erweitern. K würde dann V hypothetisch erweitern. In diesem Fall enthält K alle Bits von V und seine eigenen. Wie viele Bits sollte eine Variable vom Typ V haben? Die Anzahl der Bits von V? Dann könnten wir keinen K-Wert darin speichern, K würde nicht passen. Alle Variablen vom Typ V sollten also groß genug sein, um auch K zu enthalten. Aber wir sollten nicht bei K aufhören, da es mehr ValueTypes geben könnte, die K erweitern – unter der Annahme, dass eine Vererbung stattgefunden hat, was aber nicht der Fall ist. In diesem Fall sollte eine Variable vom Typ V so viele Bits haben, wie das größte untergeordnete Element von V haben könnte, was zum Zeitpunkt der Kompilierung unbekannt ist. Bekannt wird es nur und erst, wenn alle ValueTypes geladen sind.

Keine Polymorphie

Da es keine Vererbung gibt, kann es keine Werttyppolymorphie geben. Es existieren jedoch noch weitere Gründe, die darauf hindeuten, dass es nicht sinnvoll ist, eine Polymorphie für Werttypen zu implementieren. Betrachten wir das obige Beispiel und stellen wir uns die Variable vor, die alle Bits des größten untergeordneten Elements von V enthalten kann. Riefen wir eine Methode für diese Variable auf, welche sollte es (während der Laufzeit) sein? Die Variable enthält keine Informationen über den Typ des tatsächlichen ValueTypes. Ist es V, ist es K oder ein anderes untergeordnetes Element? Der Compiler muss wissen, welche Methode er aufrufen soll, da es keine Headerinformationen gibt, die den Typ signalisieren würden, der zu diesem Zeitpunkt in der Variable ist.

Unveränderlichkeit

Unveränderlichkeit ist eine Designentscheidung, aber eine nachvollziehbare, sozusagen natürliche. Werttypen in Java sind unveränderlich. Unveränderlichkeit ist in der Regel eine gute Sache. Unveränderliche Objekte helfen dabei, auf saubere und threadsichere Weise Code zu schreiben. Unveränderlichkeit löst nicht alle Probleme, aber sie ist oft praktisch. Auch wenn man int als Zahl sieht, ist es ziemlich offensichtlich, dass man ihren Wert nicht ändern kann. Wenn eine Variable den ganzzahligen Wert 2 enthält, kann man den in der Variable gespeicherten Wert ändern, aber nicht den Wert selbst auf 3. Könnte man, würde im ganzen Universum plötzlich 2 mal 2 mal 2 gleich 9 ergeben. Ähnlich sieht es bei Werttypen aus. Man kann den Inhalt der Variable ändern, die den ValueType enthält, nicht jedoch den ValueType selbst. Wenn man ein einzelnes Bit ändert, hat man diesem Ansatz zufolge einen neuen Werttyp angelegt und den neuen Wert anstelle des alten gespeichert. Schauen wir uns das einfache Beispiel in Listing 1 an.

package javax0.valuetype;

public __ByValue class Point {
  public int x;
  public int y;

  public Point(int x, int y) {
    this.x = x;
    this.y = y;
  }

  public Point pushedRight(int d) {
    return __WithField(this.x, x+d);
  }

  public String toString() {
    return "[" + x + "," + y + "]";
  }
}

Dies ist ein einfacher ValueType, der eine vorläufige Syntax verwendet, die mit der Version build 11-lworldea+0-2018-07-30-1734349.david.simms.valhalla der Early-Access-Version von Java kompiliert wurde. Damit wird das „Schieben“ eines Punkts entlang der X-Achse möglich. Das Hauptprogramm, das den Werttyp verwendet, macht das, was in Listing 2 zu sehen ist.

package javax0.valuetype;

public class Main {

  public static void main(String[] args) {
    Point a = new Point(3,4);
    a = a.pushedRight(1);
    System.out.println(a);
  }
}

Wenn wir pushedRight aufrufen, hat die Variable a einen neuen Wert. Der Punkt (3,4) hat sich jedoch nicht bewegt, der zweidimensionale Raum wurde nicht verzerrt. Dieser Punkt bleibt dort für immer, nur der Variablenwert wird geändert. Wenn wir jetzt versuchen, die Zeile a = a.pushedRight(1);auf a.x = 4; zu ändern, erhalten wir einen Kompilierungsfehler, der besagt:

/.../src/javax0/valuetype/Main.java:7: error: cannot assign a value to final variable x

Dabei ist zu beachten, dass das Feld x nicht als endgültig deklariert wurde, sondern automatisch als endgültig gilt, da es sich in einem Werttyp befindet.

Die Unveränderlichkeit als Merkmal steht in starkem Zusammenhang mit der Tatsache, dass es keine Referenzen auf einen ValueType geben kann. Java könnte uns theoretisch erlauben, ein Feld eines ValueType zu modifizieren. Das Ergebnis wäre aber im Wesentlichen das gleiche: Wir erhalten einen anderen Wert. Auf diese Weise ist die Unveränderlichkeit bei Werttypen keine Einschränkung. Es geht nur darum, wie wir unser Programm schreiben und wie wir ValueTypes sehen. Wenn man sie als Werte (wie Zahlen) betrachtet, die von Natur aus unveränderlich sind, wäre das sozusagen eine gesunde Denkweise.

Probieren Sie es aus

Sie können den Early-Access-Release ausprobieren, indem Sie die JEP-Homepage besuchen und außerdem die EA-Version herunterladen. Die Builds sind für Linux, macOS und Windows für die x64-Plattform verfügbar. Die Installation ist zwar nicht so einfach wie bei den Produkten für den Handel, aber für erfahrene Java-Entwickler sollten einige Umgebungsvariableneinstellungen und das manuelle Extrahieren und Verschieben von Dateien an den richtigen Ort kein Problem sein. Sie können versuchen, Eclipse, IntelliJ oder Notepad zu verwenden, um den Quellcode zu bearbeiten, aber zumindest konnte ich mit der IntelliJ-2019.EA-Edition den Code nicht erstellen. Obwohl es sich bei dem Code um einen Fork aus dem Java-11-Quellcode handelt, erkennt IntelliJ ihn als Java 13, was übrigens ein kleiner Hinweis darauf ist, wo wir in der freigegebenen Version Werttypen erwarten können. Die Kompilierung des Codes kann manuell durch Ausführen des Befehls javac über die Befehlszeile und dann des Befehls java zum Starten der JVM erfolgen. Ich bin mit dem IntelliJ-extrahierten Ant-Skript klargekommen, obwohl ich mit Maven besser vertraut bin als mit Ant.

Beim Herumspielen habe ich einige unerklärliche Kompilierungsfehler festgestellt, wobei der Code letztendlich fehlerhaft war. Nach Änderung des Codes funktionierte mit der Kompilierung alles gut. Andere Male, als der Fehler definitiv nicht bei mir lag, waren die Fehlermeldungen gut beschrieben und leicht verständlich.

Zusammenfassung

Java entwickelt sich rasant. In den vergangenen zwei Jahren hat sich viel getan, und im Moment sind viele neue Entwicklungen im Gange, die uns in der Zukunft zur Verfügung stehen. Dazu gehört das Merkmal ValueType. Dieser Artikel beschreibt die wichtigsten Aspekte dieses Merkmals und gibt einen kurzen Ausblick auf diese neue Technologie. Java ist zudem eine der wichtigsten Programmiersprachen, vielleicht die zweithäufigste Programmiersprache im professionellen Umfeld nach COBOL. Als Java-Entwickler ist einem der Arbeitsplatz so gut wie sicher. Ständiges Lernen ist jedoch unabdingbar, wenn man professionell und up to date sein möchte. Glücklicherweise handelt es sich bei Java um Open Source und es existieren eine frei verfügbare Mailingliste, Dokumentationen, Quellcode und Testversionen von zukünftigen Versionen, lange bevor sie veröffentlicht werden. Ein leidenschaftlicher Entwickler sollte sich diese ansehen, die EA-Versionen zum Experimentieren verwenden und bereits zum Zeitpunkt des GA-Releases für den Handel die neuen Möglichkeiten kennen. Also los! Schnappen Sie sich die Valhalla-EA-Version von Java und probieren Sie sie aus.

Geschrieben von
Peter Verhas
Peter Verhas
Peter Verhas ist Senior Software Architect bei EPAM Schweiz. Er hat mehr als zehn Jahre Erfahrung in der Java-Entwicklung und mehr als zwanzig Jahre Erfahrung mit C und anderen Programmiersprachen. Zudem ist er Autor der Bücher „Java Projects“, „Mastering Java 9“ und „Java 9 Programming By Example“. Er bloggt außerdem regelmäßig in englischer Sprache (bei DZONE, Java Code Geeks und seinem eigenen Blog Javax0.wordpress.com). Peter hat einen Master in Elektrotechnik und studierte an der TU Budapest, der TU Wien und der TU Delft. Er arbeitete für Unternehmen wie Digital Equipment Corporation, T-Mobile und unterstützte die Telekommunikations- und Finanzbranche. Er war kurzzeitig Lehrer an der TU Budapest. Peter veröffentlicht auch Open-Source-Programme auf GitHub und ist Autor des ScriptBasic-Interpreters. GitHub: www.github.com/verhas
Kommentare

Hinterlasse einen Kommentar

6 Kommentare auf "Der neue ValueType in Java"

avatar
4000
  Subscribe  
Benachrichtige mich zu:
S. Waldmann
Gast

Kann es sein, dass der Autor „effektiv“ mit „effizient“ verwechselt hat? Effektiv bedeutet „hat einen Effekt, eine Auswirkung“. Wären Value Types nicht effektiv, hätten sie keine Auswirkung und könnten genauso gut weggelassen werden ohne dass sich etwas ändert.

Ist dagegen „ressourcenschonend“ bzw. „performant“ gemeint, wäre „effizient“ der korrekte Terminus.

kthxbye
Gast

laut Duden steht effektiv auch für „lohnend, nutzbringend“

S. Waldmann
Gast

Der Kontext lässt allerdings darauf schließen dass es hier schon um Effizienz geht (z.B. bessere Performance durch Caching)

bughunter
Gast

war das vielleicht ursprünglich ein englischer Artikel?
„Feld x nicht als endgültig deklariert“?
final ist ja ein keyword und wird eher nicht übersetzt.

S. Waldmann
Gast

Mir ist schon mehrfach aufgefallen dass englische Begriffe fälschlicherweise ins Deutsche übersetzt werden wie letztlich sogar der Name einer Exception. Scheint ein Automatismus der Redaktionssoftware zu sein

java-freund
Gast

// Universum plötzlich 2 mal 2 mal 2 gleich 9
Vermute ich richtig, das 27 gemeint war?