Kritik der Java Technologie

Es gibt einen englischsprachigen Artikel in dem einige interessante Kritikpunkte zu Java stehen:

Einen davon finde ich wirklich interessant: Java hat keine "struct"s die man aus C kennt. Mit dem struct Schlüsselwort kann man mehrere Typen zusammenfassen. Die sind ähnlich wie Klassen, können aber auch auf dem Stack erzeugt werden (ganz ohne Heap).
Z.B. könnte man sowas schreiben:

//gewöhnlicher java code: 
public static void foo(){
    int x=0;
    int y=1;
    bar(x, y);
}
public static void bar(int x, int y){}

//wäre mit structs äquivaltent zu:
struct Point{
    int x;
    int y;
}

public static void foo(){
    //hier ist "new" nicht erforderlich. Die variablen x und y werden als lokale variablen deklariert.
    Point p;
    p.x=0;
    p.y=1;
    bar(p);
}
public static void bar(Point p){}

bei diesem Beispiel ist ein struct reiner „syntaktischer Zucker“, der Kompiler kümmert sich um die deklaration der lokalen Variablen. Der Kompiler müsste sich auch um die übergabe solcher Strukts als Parameter kümmern in dem er für diesen die richitige Anzahl an Parametern synthetisiert.

Interessanter wäre aber die Deklaration von struct-Arrays:

//Gewöhnlicher java code:
Object[] arr=new Object[4];
arr[0]="key1";
arr[1]=42;
arr[2]="key2";
arr[3]=43;
//hier ist ein cast notwendig:
Integer value=(Integer)arr[1];

//struct äquivalent:
struct Entry{
    String key;
    Integer value;
}
//der kompiler erzeugt hier ein array ungefähr so: new Object[2 * sizeof(Entry)];
Entry[] arr=new Entry[2];
//"new Entry" ist nicht erforderlich
arr[0].key="key1";
arr[0].value=42;
arr[1].key="key2";
arr[1].value=43;

//und hier wird es spannend, da der Kompiler genau weiss welche typen der struct definiert ist hier kein cast erforderlich:
Integer value=arr[0].value;

Ich bin mir nicht sicher ob die JVM selbst einen cast vorschreibt bei dem obigen Besipiel, aber es wäre interessant den ByteCode zu generieren ohne den Cast, also an den Stellen wo man sicher ist welche Typen man im Array hat. Somit könnte man eine HashMap implementieren die nicht mehr die Klasse Entry braucht. So eine HashMap Implementation wäre sicherlich viel schneller als die aus dem JDK.

Da könnte etwas dran sein. Aber es ist, wie geschrieben, syntaktischer Zucker, und es könnte das Typsystem etwas aufweichen.

:pray: wir, dass das so bleibt…

Prinzipiell suchst du nach so einer Klasse, die aber nicht vorhanden ist:

import java.util.Map;

public class KeyValue<K, V> implements Map.Entry<K, V>
{
    private K key;
    private V value;

    public KeyValue(K key, V value)
    {
        this.key = key;
        this.value = value;
    }

    public K getKey()
    {
        return this.key;
    }

    public V getValue()
    {
        return this.value;
    }

    public K setKey(K key)
    {
        return this.key = key;
    }

    public V setValue(V value)
    {
        return this.value = value;
    }
}

https://stackoverflow.com/a/29438460

Ich bin mir unsicher, warum man eine „Tupel“-Klasse in Java „immer“ „selber schreiben muss“, und warum es noch nichts ootb dafür gibt.

Vielleicht hat da ein anderer (@Marco13 vielleicht) auch eine Idee, und kann das Thema „struct s auf dem Stack“ noch einmal beleuchten.

Grüße

Ja die struct’s würden die Sprache stark verkomplizieren. Deshalb habe ich mich gefragt ob die JVM solche einfache Klassen nicht automatisch wegoptimieren kann? Zum Beispiel in den Methoden wo eine klassintanz erzeugt wird nur innerhalb der Methode.

Ich bin ein bißchen in einem Trilemma. Einerseits habe ich mich mit einigen Punkten so lange auseinandergesetzt, dass ich zwar (zu den meisten im Wikipedia-Artikel genannten, aber auch) zu dem speziellen Punkt, um den es hier bisher geht, etwas sagen könnte. Andererseits habe ich da zu einigen der letzten/neuesten Entwicklungen ein bißchen „den Kontakt verloren“. Es passiert so viel, und ein normaler Mensch kann seinen Lebensunterhalt nicht damit verdienen, dass er da up to date bleibt. Und wiederum andererseits weiß ich über das alles gerade so viel, dass ich weiß, dass ich nichts weiß, und man die Fragen, die damit verbunden sind, vieeel weiter auseinanderpflücken müßte, um etwas fundiertes dazu sagen zu können.

Aber kurz:

Deshalb habe ich mich gefragt ob die JVM solche einfache Klassen nicht automatisch wegoptimieren kann?

Ja, bis zu einem gewissen Grad, und das wird auch schon gemacht - und zwar schon seit einer ganzen Weile. Ein großer Schritt wurde da in Java ™ HotSpot Virtual Machine Performance Enhancements gemacht (ja, Java 7!). Seitdem ist die Zeit nicht stehengeblieben, aber was daran alles noch gemacht wurde, weiß ich nicht.

Das Thema structs… damit habe ich mich auf verschiedenSTen Ebenen recht weit auseinandergesetzt. Einerseits bei sowas wie GitHub - gpu/JOCLStructs: Support for structs in JOCL („echte“ structs, mit verschiedenen Elementtypen), andererseits das, was man eher „Tupel“ nennen würde (also mehrere Elemente des gleichen Typs), nämlich in nd-tuples von GitHub - javagl/ND: Multidimensional primitive data structures .

Noch kurz die übliche „CB-hat-mal-wieder-was-von-sich-gegeben“-Reaktion…

Erstens könnte man hinterfragen, ob das denn so bleiben sollte. Andererseits gibt es AbstractMap.SimpleEntry (Java Platform SE 8 ) . Und wieder andererseits hast du (vielleicht auch ich, aber ich bin mir ziemlich sicher: du) die „Ebene“ vollkommen falsch verstanden, auf der diese Unterhaltung stattfindet. Wow, man kann eine Klasse erstellen, die zwei Fields hat. Was ist der Punkt?
Wie auch immer…

Die Details einer „echten“ Unterstützung von structs auf der Ebene der Sprache (und, eng damit verbunden, aber konzeptuell glücklicherweise strikt getrennt, auf der Ebene der virtuellen Maschine) sind ungeheuer kompliziert. Mit jemandem, der sowas wie Value Types for Java zumindest gelesen hat, könnte man darüber vielleicht eine Unterhaltung führen, die etwas Substanz hat, aber … wie man am Datum schon sieht: Das ist lange her (und ich habe wohl vieles schon wieder vergessen). Der grundsätzliche Gedanke, der dort mit dem Begriff „Value Types“ beschrieben ist, ist dort aber recht gut und kompakt zusammengefasst, und einige der Fragen, die sich stellen, einleuchtend angedeutet. Kürzlich gab es dazu ein Update, mit dem aktuellen Stand der Entwicklungen: 02-object-model (aber das habe ich, zugegeben, auch noch nicht gelesen…)

1 „Gefällt mir“

Ich glaube, dass es irgendwann Mal so was geben wird, zumindest klingt es für mich in dem Konzept zu Data Classes and Sealed Types for Java. Dort heißt es:

Are records the same as value types?
With value types coming down the road through Project Valhalla, it is reasonable to ask about the overlap between (immutable) data classes and value types, and as whether the intersection of data-ness and value-ness is a useful space to inhabit.
Records and value types have some obvious similarities; they are both immutable aggregates, with restrictions on extension. Are these really the same feature in disguise?
When we look at their semantic goals, we can see that they differ. Value types are primarily about enabling flat and dense layout of objects in memory. In exchange for giving up object identity (which in turn entails giving up mutability and layout polymorphism), the runtime gains the ability to optimize the heap layout and calling conventions for values. With records, in exchange for giving up the ability to decouple a classes API from its representation, we gain a number of notational and semantic benefits. But while some of what we give up is the same (mutability, extension), some values may still benefit from state encapsulation, and some records may still benefit from identity, so they are not the exact same trade. However, there are classes that may be willing to tolerate both restrictions, in order to gain both sets of benefits – we might call these value records. So while we wouldn’t necessarily want to only have one mechanism or the other, we certainly want the mechanisms to work together.

Records gibt es ja mittlerweile schon (zumindest als Preview im aktuellem JDK) zu den value types konnte ich keine Pläne zur Einführung finden. Zwar würden diese value records auch nur im Heap liegen, aber dort dann wesentlich besser zum Auslesen sein.

1 „Gefällt mir“

Wow, vielen Dank für diesen Wertvollen Link zu value types. Also ist das tatsächlich ein Thema in Java an dem aktiv gearbeitet wird. Ich habe nicht den ganzen Artikel gelesen, der ist einfach nur sehr lang, aber ich habe vom Projekt Valhalla erfahren und unter anderem diesen Artikel gefunden:

http://cr.openjdk.java.net/~briangoetz/valhalla/sov/02-object-model.html

Da gibt es unter anderem diese Syntax dafür:

inline class Point {
    private int x;
    private int y;

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

    public int x() { return x; }
    public int y() { return y; }
}

Ich hoffe, dass es bald in die Sprache einfliesst, das wird Java auf einen ganz anderen Level erheben.

EDIT: viele aspekte kann die JVM auch schon von alleine, aber ich wüsste nicht wie so eine inline klasse als return typ angegeben werden könnte. Da bräuchte die JVM eine zusätzliche return instruction

Es geht um den Umstand, dass man dazu „gegängelt“ wird, so eine Klasse selber zu schreiben, weil so etwas die Standard Library nicht beinhaltet.

Auf der ersten Ebene könnte man sich erstmal damit beschäftigen, was da ist, was nicht da ist, und was verändert werden könnte. Daher war ja meine Anmerkung nicht falsch.

Dass es einen geiwssen Bedarf für „Tuple-Klassen“ (oder auch „Pair“) gibt, ist klar (es gibt auch Pair (JavaFX 8) ). Aber es ja auch nicht darum, dass man in C „gegängelt“ wird, seine struct Point { float x, y; } selber zu schreiben. Es geht hier (und im Wiki-Artikel) um die Möglichkeit der Erweiterung der Sprache an sich (und der VM). (Lies Value Types for Java - ist eine gute Einführung).

@anon65336368 Den link hatte ich noch nicht auf dem Schirm - wobei ich nicht beschwören könnte, dass ich ihn noch nicht gesehen hatte, weil… wenn ich ihn gesehen hätte, hätte ich wahrscheinlich gedacht: „Ah, die Value Types haben sie jetzt in ‚Data Classes‘ und ‚Sealed Types‘ aufgedröselt“ :smiley: Die genaue Abgrenzung wird vielleicht nach dem Lesen des Links klarer, aber es gibt offensichtlich einen großen Overlap, wie der zitierte Abschnitt auch sagt.

Aber das sind dann halt Punkte, auf die sich mein „Trilemma“ bezog: Um da tiefer drüber reden zu können, müßte man alles, was dort gesagt wird, besser verinnerlichen.

Auf der oberflächlichen Ebene kann man einfach (als „Kritik“) sagen: Ja, in Java gibt es kein struct. Man kann dann argumentieren, dass einige Dinge, die in C/C++ mit struct gehen, in Java einfach nicht möglich sind. Aber wenn man (wie John Rose und Brian Goetz) dann die Frage beantworten will, wie es aussehen soll, wenn es „sowas“ geben soll, muss man halt sehr, sehr genau klar machen, was man damit meint.

Wenn es nur um „syntaktischen Zucker“ ginge, könnte man hier auch auf https://objectcomputing.com/resources/publications/sett/january-2010-reducing-boilerplate-code-with-project-lombok#data verweisen: Sowas wie

@Data
public class Point {
    private final double x;
    private final double y;
}

reicht da schon, um ein vollwertiges Java-Objekt zu erstellen, mit Konstruktor, Setter/Getter, hashCode, equals und toString.

Aber das hat eben (auch wieder) nichts mit einer Erweiterung der Sprache zu tun, in dem Sinne, dass damit Datenstrukturen oder Verhaltensweisen (der VM) modelliert werden könnten, die bisher nicht modelliert werden können.

Records gibt es ja mittlerweile schon (zumindest als Preview im aktuellem JDK) zu den value types konnte ich keine Pläne zur Einführung finden. Zwar würden diese value records auch nur im Heap liegen, aber dort dann wesentlich besser zum Auslesen sein.

Mit JDK16 (seit März) ist das kein Preview mehr sondern offizieller Bestandteil vom Java (JDK16+) somit wird das auch Teil vom JDK17 (LTS) werden…

Ich persönlich halte die Notwendigkeit von Tuple im JDK für falsch …
Wie auch hier beschrieben:

Some readers will surely be thinking at this point: if we „just“ had tuples, we wouldn’t need data classes. And while tuples might offer a lighter-weight means to express some aggregates, the result is often inferior aggregates.
Classes and class members have meaningful names; tuples and tuple components do not. A central aspect of Java’s philosophy is that names matter; a Person with properties firstName and lastName is clearer and safer than a tuple of String and String.

Das ist am Ende des Tages genau der Punkt, der geklärt werden muss.

Was möchte ich mithilfe von struct erreichen?

Ich könnte jetzt mal ganz einfach sagen. Wozu? Es gibt Klassen. Somit brauche ich kein struct aus C…

Hm… also bitte nicht falsch verstehen:

Jedem Entwickler die mir solch einen Code liefern würde, würde ich Vorschlagen sich das mit dem Entwickler Job nochmal zu überlegen.

//hier ist ein cast notwendig:
Integer value=(Integer)arr[1];

Ja da ist ein Cast Notwendig, da Java (Java Compiler) weiß, dass das Array vom Typ Object ist und hier eine Konvertierung (Cast) in Integer gemacht wird(Hier muss ich dem Compiler explizit Sagen, dass ich selbst weiß was ich tue (so hoffe ich das jedenfalls)!!). Das ist immer ein Punkt für potentielle Fehler (ClassCast exceptions etc.) sehr harte Fehlersuche…). Hier verläßt man die Type-Safety des Compilers!!!

  1. Object Verwendung?
  2. Zwei unterschiedliche Typen innerhalb eines Arrays?
  3. Welche Bedeutung haben „key1“ und 42 ? Was wird repräsentiert?..

Ich würde dann je nach Kontext eine entsprechende Klasse erzeugen wie z.B.:

class EntryItem {
  private final String key;
  private final Integer value;
  EntryItem(String key, Integer value) {
   ...
  }
  String key() { return this.key; }
  Integer value() {return this.value; }
}

(Absichtlich kein public gewählt. Sichtbarkeit einschränken und nur dann wirklich public machen, wenn es nötig ist).

(Mit JDK16 ginge es noch einfacher record EntryItem(String key, Integer value) {};)

So und dann frage ich mich am Ende: Wozu soll es struct geben?

  @Test
  void using_usual_class() {
    EntryItem[] structEntryArray = new EntryItem[2];
    structEntryArray[0] = new EntryItem("key1", 42);
    structEntryArray[1] = new EntryItem("key2", 43);
    Integer integerValue = structEntryArray[0].value(); //Hier habe ich wieder Type-Safety!!
  }

  class EntryItem {
    private final String key;
    private final Integer value;

    EntryItem(String key, Integer value) {
      this.key = key;
      this.value = value;
    }

    String key() {return this.key; }
    Integer value() {return this.value; }
  }

Jetzt kommt genau der spannende Punkt: structEntryArray[0] = new EntryItem("key1", 42);
wenn es jetzt nich nötig wäre hier new EntryItem(..) zu schreiben, dann kommen wir aber mehr zu
den ValueTypes womit es dann möglich ist ein Array im Speicher hintereinander abzulegen… Das hätte einige Vorteile… (Performance etc.)

Die Weichen sind gestellt…

Weiterhin ist der Artikel and den meisten Stellen schlicht veraltet…

Operatoren Überladung? Ja geht in C++ XXX operator+(const XXX&);… dann eventuell noch die Non-Const Variante usw.
Mir fällt für Operatoren Überladung genau ein Use Case ein. Mathematische Funktionalitäten (Complex /Brüche usw. etc. addition usw.) ?

Multidimensionale Array dafür gibt es dann die Vector API (ja noch in incubator…)…

Memory Zugriff ist in JDK17 EA enthalten (preview)… (Die Größe ist ein „long“).

Ja ein Punkt dem kann ich zustimmen ist das „fehlen“ von unsigned typen… Aber die Frage ist, wann ich die brauche? Hardware Zugriff? Dann ist aber meiner Meinung nach die Frage, ob hier Java das richtige ist und nicht eventuell andere Sprachen besser geeignet sind (Go, Rust, oder auch C/C++)?

Doch solch eine Klasse existiert: AbstractMap.SimpleEntry<K,V>… und auch eine Variante AbstractMap.SimpleImmutableEntry<K,V>…(seit JDK6)

Weiterhin verletzt die angegebene Klasse public class KeyValue<K, V> implements Map.Entry<K, V> den Kontrakt Map.Entry, da hier eine setKey angegeben wurde…Das Interface Map.Entry hat aberk eine Methode setKey.. es gibt nur ein setValue(...)

Nicht jedes Tupel muss auch ein Key-Value-Pair sein. Grundsätzlich ist die Klasse richtig, aber das impl. Entry verwirrt mich jetzt auch etwas. Ich denke, man wollte die Klasse nicht partiell immutable machen.

Weiterhin hab ich nicht aufs Datum geschaut und dass es mittlerweile etwas dafür gibt (das wohl auch den Anwendungszweck erfüllt). :wink:

Da gibt’s einiges wozu ich mehr schreiben würde/werde.

Ganz kurz vorneweg:

Jedem Entwickler die mir solch einen Code liefern würde, würde ich Vorschlagen sich das mit dem Entwickler Job nochmal zu überlegen.

Ich gehe davon aus, dass das, was neoexpert dort angedeutet hat, gerade ein Beispiel sein sollte für etwas, was zwar ~„technisch geht“… aber … halt schöner gehen sollte.

Und (auch erstmal kurz) zu den anderen Punkten:

Jein. Es gibt durchaus viele Bereiche, wo Tupel explizit als solche verwendet werden. Sicher nicht bei einer 08/15-Business-Anwendung, und der „Extremfall“ ist, dass man etwas sehr theoretisch/mathematiknahes modellieren will. Aber eine gewisse Vorsicht ist gerechtfertigt: Wenn sowas wie https://www.javatuples.org/ teil der Standard-API wäre, dann würden Leute das verwenden, um murxigen Code zu schreiben.

(Ein Pair habe ich schon gelegentlich vermisst. Aber… „häufig“ mit der Lösung, dass dort dann ein ObjectWithDistance { T, double } oder ObjectWithIndex { T, int } nötig gewesen wäre, und dann kommt halt eine andere Schwäche von Java zum Tragen, nämlich, dass es kein Pair<T, double> geben kann, sondern nur ein Pair<T, Double> …)

Ich bin nicht sicher, ob das ein statement ist, um im soktratischen Sinne eine Diskussion anzuregen. Aber es gibt viele gute, technische Gründe - und auf einen wichtigen kommst du dann im Folgepost zu sprechen. Ein wichtiger Punkt ist (etwas unpräzise formuliert, aber um’s einfach zu machen) die Frage, ob

EntryItem[] structEntryArray = new EntryItem[2];
structEntryArray[1].value = 123;

gehen sollte, oder ob’s ihn da mit einer NPE raushaut. Die Möglichkeit, einen Struct-Array als einen zusammenhängenden Speicherlock zu haben (statt eines „Arrays von Pointern“, die kreuz und quer in den Heap zeigen), ist recht wichtig. Das hat dann (komplexe, und nicht sooo offensichtliche) Verbindungen zu OpenJDK: Panama … (und du hast auch schon auf die Vector API verlinkt…).

Die genaue semantische Abgrenzung zwischen „struct“, „value type“, „record type“ und „sealed type“ in diesem und ähnlichen Zusammenhängen müßte ich mir erst draufschaffen/auffrischen. Bin da leider nicht auf dem neuesten Stand…

Das ist ein zweischneidiges Schwert. Ähnlich wie bei den Tupel-Klassen: Es kann sinnvoll sein. Aber man muss davon ausgehen, dass Leute da dann den murxigsten Mist machen würden:

myWindow += button; // Adds the button to the window - yay!

Jemand, der bei den Worten „Gruppe“, „Ring“ und „Körper“ nicht an seine Algebra-Vorlesung zurückdenkt, sollte tunlichst die Finger von Operatorüberladung lassen. Aber für spezielle Dinge, wie GitHub - JOML-CI/JOML: A Java math library for OpenGL rendering calculations oder auch sowas wie result = bigDecimalA / bigDecimalB wäre es halt schon sehr praktisch…

Dazu ein kleiner Outtake aus der Spezifikation von Oak :

OakUnsigned

Sie hatten Recht :slight_smile: Aber… man braucht es wirklich selten.

Als Kontrast dazu, eine Sache, die das Arbeiten mit C++ fast unmöglich macht, ist Fundamental types - cppreference.com und Fixed width integer types (since C++11) - cppreference.com . Man schreibt unschuldigsten code, und das ganze geht dann an den Build-Server mit MSVC, GCC und Clang, und egal was man macht: Irgendeiner beschwert sich immer über irgendeine integer-typ-Konvertierung. Designfehler der C++ - Standard-API (unsigned typen wie size_t im interface…) multiplizieren die Schwierigkeiten. Da lob’ ich mir die Klarheit und Einfachheit von Java: Ein int ist ein int, runter-spezifiziert bis zum letzten Bit.

Ja ich nehme auch mal an, das structs eher als Mittel zur Kommunikation mit anderen Sprachen oder Systemen (außerhalb der JVM) dient oder dienen soll . Man siehe sich Project Panama an, Valhalla oder eben die GraalVM an, bei der Oracle ganz gezielt auf Polyglote Programmierung zielt und Ausführung auf der GPU und SIMD Befehlen.

In OpenGL gibt es durchaus structs auf Shader-Seite, aber mit einem Java Client kann man solche eben nicht als ganzes direkt bedienen.

Das gäbe, theoretisch, Java die Möglichkeit benutzerdefinierte Daten-„Objekte“ auszutauschen.

Aber das ist alles nur Vermutung und Spekulation und wird am Ende darauf hinauslaufen ob man es richtig macht. Weil abgesehen davon fällt mir auch kein Grund ein.

Mag sein, aber du weisst selbst wie kompliziert die Kommunikation mit C Programmen sein kann. Musste ich erst zuletzt wieder feststellen.

Man könnte natürlich argumentieren, warum die alle überhaupt unsigned Datentypen haben und verwenden. Sollen sie es doch wie in Java machen - da funktioniert es ja auch so.

Nun, gerade bei Panama ist/war ja ein Ziel, für SIMD nicht mehr auf andere Sprachen zurückgreifen zu müssen. Für SIMD (und der Begriff ist eigentlich zu eng - etwas weiter könnte man ~„datenparallele Programmierung“ sagen) ist’s halt blöd, wenn bei einem MyStruct[]-Array die Daten kreuz und quer im Speicher verteilt sind.

Sicher könnte die VM (und hat das sicher auch schon) sich Mühe geben, die Daten dicht zu packen, und unter der Haube dafür zu sorgen, dass das ganze schön mit dem Cache der jeweiligen Hardware zusammenpasst und ggf. auch schon Hardware-eigene SIMD-Befehle verwenden. Aber das ganze sauber in einer Form anzubieten, die den sweet spot von „Kontrolle“, „Flexibilität“, „Performance“ und „Einfachheit“ trifft, den wir von Java gewohnt sind und erwarten, ist alles andere als leicht.

Man könnte natürlich argumentieren, warum die alle überhaupt unsigned Datentypen haben und verwenden.

Man kann für unsigned argumentieren - allerdings sind die meisten Argumente, die man da findet, mit irgendwelchen Altlasten verbunden, oder beziehen sich auf sowas wie Protokolle, wo es dann fast schon wieder egal ist: Wenn man 0xF000BABE in einen int packt, dann ist das keine „negative Zahl“, sondern einfach eine Folge bits, deren Bedeutung offen bleibt. Wenn man damit rechnen will, muss man ggf. aufpassen, aber es ist ein geringer Preis im Vergleich zum int-Typen-Krampf bei C++.

Ich sehe durchaus die Nachteile, wenn man exzessiv Tuple anstelle von dedizierten Klassen verwendet, möchte aber darauf hinweisen, dass es durchaus genügend Beispiele gibt, wo es einfach darum geht, dass man ein „Bündel“ von Werten braucht, die semantisch nichts miteinander zu tun haben, und eine gemeinsame Klasse keinerlei Vorteil gegenüber einem Tupel hätte, sondern nur umständlicher und weniger intuitiv zu bedienen wäre:

  • Zippen von zwei Collections
  • Rückgabe zweier Werte von einer Funktion oder Methode
  • Uncurrying einer BiFunction in eine Function
  • Kategorientheoretische Abstraktionen (z.B. BiFunctor, BiApplicative, ReaderMonad, WriterMonad, StateMonad)
  • „optische“ Abstraktionen (z.B. Linsen, Prismen, Iso)

Meiner Meinung gehören Tuple ins JDK, denn es gibt genügend valide Anwendungsfälle. Natürlich können sie wie andere Klassen auch missbraucht werden, und ich hätte nichts gegen einen fetten Warnhinweis (wie bei Optional), aber sie ganz wegzulassen ist meiner Meinung nach ein Fehler.