Nö, wenn ich eine Methode habe die nur was ausgeben soll, kann man die generischste Oberklasse verwenden - Collection. Es gibt keinen Benefit sich da einzuschränken.
Nö, wenn ich eine Methode habe die nur was ausgeben soll, kann man die generischste Oberklasse verwenden - Collection. Es gibt keinen Benefit sich da einzuschränken.
publicclassGenericsTest{privateStringprintCollection(Collection<?extendsComparable> collection){return"";}publicvoidtestIt(){List<Student> list =newArrayList<>();printCollection(list);}}
public static <T extends Comparable<T>> void doSomething(Collection<T> elements) {
Denn das ist doch, was ich verstanden habe. Es geht um einen Typ T, der Comparable<T> implementieren soll. Und davon soll eine Collection übergeben werden ...
Also in einem Beispiel nehmen wir einfach eine KLasse, die Comparable implementiert:
Und testen dann den Verwendung mit einer generischen Methode:
Java:
importjava.util.ArrayList;importjava.util.Collection;importjava.util.List;publicclassTest{publicstaticvoidmain(String[] args){List<Student> list =newArrayList<>();doSomething(list);}publicstatic<TextendsComparable<T>>voiddoSomething(Collection<T> elements){}}
Daher ist das doch eigentlich 1:1 wie beschrieben implementierbar.
Und wenn nur das Interface Collection benötigt wird, dann macht es absolut keinen Sinn, sich da weiter einzugrenzen. Da wäre es mal interessant, Argumente oder ein konkretes Beispiel zu bekommen.
Edit:
Damit das Beispiel einen Sinn ergibt, einfach noch etwas aufgebohrt. Student hat nun noch ein name mit allem drum und dran. Und dann habe ich einfach mal ein "printSorted" als Beispiel genommen. Da macht es durchaus Sinn, eben kein Iterator<T> als Parameter zu haben, denn wir wollen ja ein Stream als Möglichkeit haben. Dann wäre das sowas geworden:
Also nur um das noch einmal ausführlich zu beschreiben:
Parameter ist einfach eine Collection<T>.
T soll aber eingeschränkt sein auf Klassen, die Comparable<T> implementieren. So eine Einschränkung muss nicht bei der Verwendung von T sondern bei der Deklaration von T beschrieben werden. (JLS 8.1.2 falls man sich das im Detail in der JLS ansehen möchte)
Also nur um das noch einmal ausführlich zu beschreiben:
Parameter ist einfach eine Collection<T>.
T soll aber eingeschränkt sein auf Klassen, die Comparable<T> implementieren. So eine Einschränkung muss nicht bei der Verwendung von T sondern bei der Deklaration von T beschrieben werden. (JLS 8.1.2 falls man sich das im Detail in der JLS ansehen möchte)
Collection bietet genügend Methoden, die eine Nutzbarkeit ermöglichen.
I. d. R. sollte man einen Typ wählen, der die kleinste Übereinstimmung mit den innerhalb benötigen Anforderungen hat, um damit eine größtmögliche Nutzbarkeit für den Anwender zu erreichen (die Auswahl an nutzbaren Typen steigt). Möchte man innerhalb z. B. nur über die Elemente iterieren, dann würde auch Iterable noch ausreichen.
Collection im Produktivcode zu verwenden, ist einfach nur falsch. 😂 Manchmal denke ich, die Leute schreiben einfach irgendetwas ohne auch nur den Hauch einer Ahnung zu haben. 😄
Collection im Produktivcode zu verwenden, ist einfach nur falsch. 😂 Manchmal denke ich, die Leute schreiben einfach irgendetwas ohne auch nur den Hauch einer Ahnung zu haben. 😄
Wir hatten schon vorher Deine Position verstanden, nur eben fehlen bisher Argumente.
Und das mit dem "Leute schreiben einfach irgendetwas ohne auch nur den Hauch einer Ahnung zu haben." disqualifiziert Dich, denn sachlicher Umgang miteinander scheint Dir nicht möglich zu sein. Und wenn man sich das Java Framework anschaut (unser Handwerksmaterial sollten wir doch kennen, oder?), dann findet man dies übrigens ebenso. Siehe z.B. List.addAll.
Sorry, aber:
a) habe ich sogar Code als Beispiel gebracht. Habe dazu extra das abstrakte mit minimalem Code erweitert, so dass da eine Methode etwas Sinnvolles macht.
b) Natürlich ist eine Nutzung der Generics wichtig, um den Typ richtig zu erfassen. Denn das Ziel ist ja, dass die Elemente untereinander vergleichbar sind. Also will man eben ein Student implements Comparable<Student> haben. Und man möchte ggf. auch mit anderen Klassen vergleichen können. Das Generic weg zu lassen führt schlicht dazu, dass es mit einer Klasse die Compareable auf sich selbst implementiert, nicht mehr aufgerufen werden kann. (Und Code-Analyse Tools sollten Dir den Code um die Ohren hauen - denn Du nutzt eine Generische Klasse ohne Generics)
Ja das wäre es mit Collection<Comparable> auch... Ich sage nicht, dass es falsch wäre, aber ggf. überflüssig. Und deine Tools interessieren mich nicht so sehr, eher richtiger Code.
Und an welcher Stelle hat der TE bitte ein Beispiel gebracht? Da kam gar nix. Deshalb ist das Thema für mich auch erledigt. Entweder kann oder will der TE nichts lesen. Beides stellt eine Missachtung unsgegenüber dar. Aber naja, es haben sich ja anscheinend ein paar "kluge" gefunden, die dem TE dennoch antworten.
Sorry, aber der TE hat sein nicht funktionierendes Beispiel gebracht. Da ist seine Absicht durchaus zu erkennen. Wenn Du dies nicht erkennst, dann hättest Du vielleicht freundlicher nachfragen sollen, statt hier nur Stunk zu machen.
Und ICH habe dann ein konkreteres Beispiel gebracht, wie es aussehen könnte.
Du solltest Dich intensiver mit Generics beschäftigten und versuchen, Dich besser auszudrücken. Das Collection<Comparable>, das Du hier immer erwähnst, funktioniert so nicht. Es ist natürlich - so wie von @temi bereits angemert, ein Collection<? extends Comparable> notwendig.
Und um da Diskussionen vorzubeugen, probir es doch einfach einmal aus. Student Class habe ich schon gebracht. Die Test Klasse passen wir dann an, so dass der Parameter wir von Dir gefordert ist:
publicstaticvoidmain(String[] args){List<Student> list =newArrayList<>();
list.add(newStudent("ZZZ"));
list.add(newStudent("AAA"));
list.add(newStudent("MMM"));
list.add(newStudent("BBB"));
list.add(newStudent("YYY"));printSorted(list);}
Tja - schade. Funktioniert leider nicht ...
Damit dies übersetzt werden kann, ist der Parameter auf Collection<? extends Comparable> zu ändern.
Und da Du die Implemetation ohne Generics / Typsicherheit besser findest (Das ist Dir überlassen. Das ist Deine pers. Meinung), möchte Ich Dir nur einmal das Problem mit der fehlenden Typsicherheit und den möglichen ClassCastExceptions vor Augen führen:
Verändern wir die Klasse Student einfach mal: public class Student implements Comparable<Integer> {
Damit ist der Code mit dem Collection<? extends Comparable> übersetzbar und kann aufgerufen werden.
Aber zur Laufzeit haben wir dann natürlich eine ClassCastException: Exception in thread "main" java.lang.ClassCastException: class Student cannot be cast to class java.lang.Integer
Ziel der Typsicherheit ist nu einmal u.A., dass so Laufzeitprobleme verhindert werden. Dies funktioniert mit Generics. Wenn man diese verwenden will, dann kann man dies. Das Vorgehen ist ganz einfach und das habe ich aufgezeigt und dann auch direkt noch kurz erläutert. Das hat dem TE offensichtlich geholfen und dafür hat er sich auch bedankt (#15).
Collection im Produktivcode zu verwenden, ist einfach nur falsch. 😂 Manchmal denke ich, die Leute schreiben einfach irgendetwas ohne auch nur den Hauch einer Ahnung zu haben. 😄
Der zweite Satz trifft gerade auf dich zu. Warum ist es falsch? Welchen Vorteil habe ich, wenn ich nicht Collection im Beispiel verwende? Wenn das so klar ist, sollte das ja einfach begründbar sein.
Generics verwenden, um bei Anfängern Programmierfehler zu vermeiden: Hierbei kann man auch geteilter Meinung sein, man kann theoretisch immer ein Beispiel finden, wie man eine Methodensignatur falsch aufrufen kann. @kneitzel Ich stimme dir aber zu, es sollte zumindest funktionieren/also kompilierbar sein. Ich hab das nicht getestet.
SSCCE: Wenn man nicht genau weiß, was ein Begriff bedeutet, schaut man ihn nach: http://sscce.org/ Also auch, Wie man Fragen richtig stellt...
Generics und Gegen das Interface programmieren schneidet hier auch das Thema homogene oder nicht homogene Listen an... Sowie null-erlaubende und nicht-erlaubende Datenstrukturen sowie doppelte Elemente...
Wenn eine Methode beispielweise nur eine Collection<? extends Comparable> zurückgibt, dann weiß ich einfach zu wenig über den Rückgabetyp, den ich bekomme, um mit dieser "Sammlung" sinnvoll weiterarbeiten zu können. Kommt da eine Map, Set, List oder Queue zurück? Zu viele Fragezeichen...
Wenn eine Methode beispielweise nur eine Collection<? extends Comparable> zurückgibt, dann weiß ich einfach zu wenig über den Rückgabetyp, den ich bekomme, um mit dieser "Sammlung" sinnvoll weiterarbeiten zu können. Kommt da eine Map, Set, List oder Queue zurück? Zu viele Fragezeichen...
Es geht um einen Parameter - nicht um einen Rückgabewert.
Nochmal, die konkrete Frage, wo dich weigerst die zu beantworten:
Welchen Vorteil habe ich, wenn ich nicht Collection im Beispiel verwende? Wenn das so klar ist, sollte das ja einfach begründbar sein.
Das kommt letztendlich auf den konkreten Anwendungsfall an. Und weil der TE leider kein sscce hinzugefügt hat, kann man nur Vermutungen anstellen... So, und da beißt sich die Katze in den Schwanz.
Unabhängig von den einzelnen Meinungen finde ich, daß die Java-Generics bei relativ geringer Schutzwirkung sehr unhandlich zu verwenden sind.
Die Fehlermeldungen des Compilers sind auch schwierig zu verstehen.
Dabei spielt wahrscheinlich eine Rolle, dass zum Beispiel Martin Odersky daran beteiligt war, Scala-Compiler-Fehlermeldungen glelten auch als schwer verständlich, ist eben Professoren-Kram (man muss es schwer verständlich formulieren, um den Abschaum fern zu halten).
Eine Verbesserung wäre sicher declaration site variance (Es gibt dazu ein Video von einer Java-Konferenz im Netz).
Ausserdem ist das Java-Collection-Framework relativ misslungen, stammt eben aus den 90er-Jahren.
Josh Bloch hat aber auch schon dafür um Entschuldigung gebeten.
Das kommt letztendlich auf den konkreten Anwendungsfall an. Und weil der TE leider kein sscce hinzugefügt hat, kann man nur Vermutungen anstellen... So, und da beißt sich die Katze in den Schwanz.
Nein, du hast es gesagt - es ist immer falsch. Also kannst du das auch begründen, oder?
Es ist ja - laut deiner Aussage - egal was der TE machen will. Es ist trotzdem falsch. Sonst beantworte die Frage für folgende Methode:
Der TE hat ein klares Problem gehabt, hat dieses geschildert incl. seinem nicht funktionierenden Versuch.
Das war soweit auch gut verständlich - denn es gab dann Antworten dazu - und dem TE ist geholfen worden, denn er hat sich bedankt. (Daher ist hier für mich komplett unverständlich, dass dem TE Respektlosigkeit oder so vorgeworfen wird!)
Ein SSCCE vom TE zu fordern ist jedoch absoluter Nonsense. Seine Frage ist beantwortet, er ist raus. Deine Probleme interessieren den TE nicht! Aber Andere greifen Deine Punkte auf und liefern dann auch Beispiele. Das ist der Grund, wieso ich Dir auch direkt konkrete Beispiele gebracht habe. Da hattest Du also etwas ganz konkretes. Und daran konnte ich Probleme aufzeigen.
Aber zurück, was hier dann jetzt passiert:
Das eigentliche Thema wird mehrfach verdreht ... plötzlich wird was gepostet mit Generics / Interfaces als Rückgabe... Generics sind plötzlich etwas für Anfänger....
Und wir landen bei einer generellen Betrachtung von den Java Collections (Unabhängig von dieser Generics Problematik).
Das Kernproblem (so wie ich @betatwo verstanden habe) ist hier doch geworden:
Wieso bin ich bei Parametern so offen wie möglich?
Und mit dem letzten Links könnte man noch sagen: Wieso bin ich bei Rückgaben konkret?
Und das ist doch direkt ersichtlich wenn man sich das doch einmal überlegt:
Wenn die Methode mit jeder Collection klar kommt, dann macht es keinen Sinn, dies einzuschränken. Also meinem printAll ist es egal, ob da eine Liste von Studenten übergeben wird (Die Liste der besten Studenten. Also liegt eine Reihenfolge vor und so ...) oder ein Set von Studenten (Wer wird exmatrikuliert? Da kommt also jeder Student nur einmal vor. Egal wie viele Gründe es für eine Exmatrikulation geben sollte!)
Eine Beschränkung macht also keinen Sinn, da durch eine Eingrenzung des Parameters auch der Bereich, in dem es angewendet werden kann, begrenzt wird.
Bei der Rückgabe ist es ähnlich. Nur da wird die Nützlichkeit verringert. Denn ich verliere klare Informationen. Collection<Student> verliert Daten. Sind die Studenten in einer Reihenfolge? Kann ein Student mehrfach vorkommen? u.s.w. Diese Form des Verlustes will man in der Regel nicht.
(Das wird so übrigens auch in dem verlinkten SO Beitrag gesagt, so ich das beim Überfliegen richtig erfasst habe!)
Java:
publicinterfaceComparable<TextendsComparable<T>>{
Was genau willst Du damit erreichen? Was ist der Sinn davon?
Was spricht theoretisch denn dagegen, dass eine Klasse X Comparable<X>, Comparable<String>, Comparable<Integer>, ... erweitert?
Dann ist klar: X Instanzen kann ich auch mit einem String vergleichen. Wenn das Sinn macht - wieso nicht?
Wozu das weiter einschränken?
Das kann man dann auch schön erweitern. Also warum nicht sowas: public <X, Y extends Comparable<X>> printGreaterElements(Collection<Y> collection, X compareWithValue);
Dann kann ich eine Methode schreiben, die aller Werte aus der collection mit compareWithValue vergleichst und nur "größere" Werte ausgibt.
X / Y kann die gleiche Klasse sein aber es können auch unterschiedliche Klassen sein ...
Das eigentliche Thema wird mehrfach verdreht ... plötzlich wird was gepostet mit Generics / Interfaces als Rückgabe... Generics sind plötzlich etwas für Anfänger....
Und wir landen bei einer generellen Betrachtung von den Java Collections (Unabhängig von dieser Generics Problematik).
Was spricht theoretisch denn dagegen, dass eine Klasse X Comparable<X>, Comparable<String>, Comparable<Integer>, ... erweitert?
Dann ist klar: X Instanzen kann ich auch mit einem String vergleichen. Wenn das Sinn macht - wieso nicht?
Wozu das weiter einschränken?
Das kann man dann auch schön erweitern. Also warum nicht sowas: public <X, Y extends Comparable<X>> printGreaterElements(Collection<Y> collection, X compareWithValue);
Dann kann ich eine Methode schreiben, die aller Werte aus der collection mit compareWithValue vergleichst und nur "größere" Werte ausgibt.
X / Y kann die gleiche Klasse sein aber es können auch unterschiedliche Klassen sein ...
Nein, wo kommt die Class Cast Exception, wenn doch über die Generics immer der richtige Typ angegeben wurde?
Das würde super funktionieren. Und so eine Class X auch Comparable<X> implementiert ist es auch kompatibel zu der alten Nutzung, die erwartet, dass Instanzen gleicher Klasse verglichen werden.
Aber der springende Punkt ist, dass da dann vom TE Dinge erwartet werden, die so schlicht Unsinn sind. Und wenn dann der TE wegen sowas als respektlos dargestellt wird, dann ist das nicht in Ordnung.
Ebenso wie haltlose Unterstellungen, dass Andere keine Ahnung haben. In der Kommunikation gibt es halt sehr wohl Regeln. Ebenso hier im Forum. Und Nichteinhaltung hat Konsequenzen. (BTW: macht hier ggf. Auch Sinn)
Wo muss man den Compiler überlisten? Und wo sollte Deiner Meinung nach eine ClassCastException entstehen? Es wird doch genau angegeben mit welchem Typ verglichen werden kann. Und dann gibt es keinerlei Probleme mit dem Compiler ...
Also nehmen wir einfach das Beispiel von eben - hatte ja schon ein Student implements Comparable<Integer> aus Jux gebaut um die ClassCastException bei dem Collection<? extends Comparable> zu zeigen (Generics weglassen ist halt Müll!)
Das bezog sich doch auch nicht auf Dich sondern auf @betatwo.
Und ich denke, ich habe Deinen Punkt, auf den Du hinaus wolltest, jetzt evtl. verstanden. Ich hatte halt zu sehr den Bereich des theoretisch machbaren betrachtet und nicht nach Sinn bzw. nach den weiteren Auswirkungen in anderen Methoden gefragt.
Daher zwei Punkte:
1.) Ganz wichtig. An einer Stelle habe ich Unsinn geredet - da sprach ich von der Implementation eines Interfaces mit mehreren Generics. Das ist so natürlich Quatsch.
2.) Comparable als Interface muss man genau betrachten: Was soll das und wo wird es z.B. benutzt:
- Es stellt die "class natural order" da. Also wie sieht die natürliche Ordnung bei mehreren Instanzen aus. -> Daher kann das nur Sinn machen mit der eigenen Klasse. Alles andere wäre entgegen dem Sinn des Interfaces.
- Es gibt dann natürlich genügend Stellen, an denen es genau so benutzt wird. Und dann kommt natürlich auch die von Dir angesprochene ClassCastException. (Das ließe sich auch ganz einfach in dem Beispiel provozieren - einfach den Stream in der Methode noch um ein .sorted() ergänzen!)
Daher waren Deine Hinweise gold richtig und ich habe bei meinen Betrachtungen mich vor allem um die Generics selbst gekümmert und dabei das Interface selbst aus den Augen verloren!
Es ist klasse, dass Du Dich entschuldigst, aber nach meiner Meinung nicht notwendig.
Ich persönlich ziehe mich meist aus dem Thread zurück, wenn ich korrigiert wurde oder ich das Risiko spüre, mich im Ton zu vergreifen. Ist wahrscheinlich nicht korrekt von mir.
Ansonsten vielen Dank für Deine Beiträge in diesem Forum, aus denen ich auch einiges gelernt habe (Variable).
In Deinen Beiträgen steckt auch eine Menge Arbeit, nicht alle schätzen das hoch genug ein.