Menü
Avatar von Exxtreme2
  • Exxtreme2

mehr als 1000 Beiträge seit 18.10.2008

Re: Na, wer kauf denn jetzt alles das Buch?

cdonat schrieb am 09.10.2019 15:43:

Die Klasse ist halt das Standardbeispiel für "everything that is wrong with Java in a single class name". Gemeint waren allgemein komplexe Klassenhierarchien und der Java-typische Patternoverkill, wo Patterns nicht eingesetzt werden, weil man ein bestimmtes Problem lösen möchte, sondern damit auch dieses Pattern noch irgendwie mit rein gezwungen wird. Ich nehme mal an, dass du selbst aus deiner Praxis auch genug Fälle kennst, wo du nachvollziehen kannst, was ich damit meine. Vor dieser Seuche ist keine Sprache wirklich sicher und es ist auch eigentlich kein Problem der Sprache an sich, aber in Java ist das Phänomen besonders stark verbreitet, während Python und C++ vergleichsweise wenig betroffen sind.

Das ist bisschen zu einfach betrachtet. :) Man kann sich natürlich die Frage stellen, warum die das so gelöst haben über so eine Klasse. Eine Antwort wird wohl sein: weil es ging. Der Punkt ist, Java wirft dem Entwickler bei solchen Konstrukten keine Knüppel in die Beine. Ist sogar so, dass solche Kontrukte in Java besonders einfach sind. Richtig PITA bei sowas ist nämlich das Aufräumen von Ressourcen. Und das ist in Java idR. eine Nobrainer dank eines exakten GC. C# hat auch solche Konstrukte übrigens. Mit C++ ist sowas bestimmt auch möglich aber bitte erst ab C++11 und höher. Und da am Besten zu 100% C++11 und höher und möglichst keine älteren Bibliotheken. Davor sind solche Konstrukte wohl kaum beherrschbar mit C++.

cdonat schrieb am 09.10.2019 15:43:

Ich hab mir mal das Tutorial angeschaut. Natürlich kann es sein, dass ich da was fehlinterpretiere, aber ich sehe da doch vergleichsweise viel Boilerplate. Schau dir mal die Beispiele von FastAPI im Vergleich dazu an. Genau das ist auch, was ich mit eleganter API meine. In Java schreibt man noch diesen und jenen Boilerplate dazu, während man in Python nur minimal über das hinaus hinschreiben muss, als man vom Standardverhalten abweichen möchte. Die PythonAPI passt sich der Problemstellung an, während die Problemtellung an die Begrenzungen von Java (durch hinzufügen von Boilerplate) angepasst werden muss.

Ja, ist sicherlich etwas mehr Boilerplate. Aber es ist jetzt nicht so, dass ein paar Annotationen zu setzen und dann kurz den Konverter zu initialisieren jetzt das Fünffache an Code im Vergleich zu Python ist wie ein anderer User schreibt. :)

cdonat schrieb am 09.10.2019 15:43:

Gegen die Dereferenzierung von nullptr helfen smart Pointer und Checks auf nullptr an der Stelle, wo sie gesetzt werden.

Die Checks muss man ja aber setzen. Das ist schon in Java eine Plage. Die NullPointerException dürfte da die häufigste Fehlerursache sein. Und kleiner wird der Sourcecode dadurch nicht.

cdonat schrieb am 09.10.2019 15:43:

Gegen den Zugriff außerhalb der Grenzen eines Arrays, oder vectors helfen .at() statt operator[]() und Iteratoren. In mindestens 99% der Fälle iteriert man über einen Container und das macht man mit Iteratoren. In den 1% der Fällen, in denen man einen Random-Access braucht, kann man entweder manuell die Bounds prüfen, z.B. wenn man mehrere Zugriffe machen möchte, oder man verwendet eben .at(), was die bounds checkt.

Wie schon geschrieben, gibt auch Klassen, die sowas nicht haben.

cdonat schrieb am 09.10.2019 15:43:

Bis auf alte C-Arrays, kenne ich nur APIs, die entweder selber die bounds checken, oder über Methoden, wie z.B. size() dem Nutzer der Library die Bounds-Checks ermöglichen. Aber wie gesagt, man verwendet Iteratoren und hat damit ca. 99% der Fälle, in denen man in C noch einen Off-By-One Error erzeugt hätte, schon erledigt. Damit die Schleifen nicht zu mühselige Tipparbeit werden, gibt es range-based-for und auto:

Dann guck dir mal subspan() an:

https://en.cppreference.com/w/cpp/container/span/subspan

Wenn da was schief geht dann fliegt dir das um die Ohren mit undefiniertem Verhalten. Das Ding hat keinerlei zumindest optionale Sicherheitsnetze.

cdonat schrieb am 09.10.2019 15:43:

Das ist natürlich Geschmackssache, aber warum nicht einen Konstruktor verwenden?

Meine Erinnerung an Java mag von den Sun-APIs geprägt sein. Wenn man oft genug in Java einen Handler der Implementation einer API über eine Factory, die die nicht statische Methode eines Singeltons ist geholt hat, damit man damit über eine andere Factory in einem anderen Singleton dann ein konkretes Objekt dieser Implementation einer API zu bekommen, dann kommt man irgendwann schon zu dem Schluss, dass die Java-Leute solche unnötige Komplexität wirklich toll finden und wendet sich halt dann von dieser Sprache ab. Oder was ich schon an trivialen, immer praktisch gleichen getter und setter-Methoden geschrieben habe für irgendwelche Java-Beans, das geht auf keine Kuhhaut.

Das klingt irgendwie nach J2EE oder so. Das ist tatsächlich ein overenginiertes Monster und wohl der Grund warum Spring so groß geworden ist. Sowas ist aber eher nicht die Regel und mit JavaEE 5 haben sie stark nachgebessert.

cdonat schrieb am 09.10.2019 15:43:

Das würde ja bedeuten, dass in Java nur vergleichsweise unfähige API-Entwickler unterwegs wären. Das halte ich für sehr unwahrscheinlich. Wenn man sich dann noch anschaut, welche Sprachfeatures die API-Entwickler in anderen Sprachen einsetzen, um zu eben diesem Ziel zu kommen, dann liegt der Schluss schon nahe, dass das fehlen dieser Features in der einen oder anderen Form der Grund ist, warum Java APIs so viel weniger elegant sind.

Wie schon geschrieben, die Mentalität war zu SUNs Zeiten eine andere was APIs angeht. Die wollten möglichst einfache und flexible Lowlevel-APIs, die sich als Baustein für höherlevelige APIs eignen. Diese Zwecke erfüllten sie gut aber sie waren für den Entwickleralltag nicht so der Hit. Deshalb gibt es auch sowas Google Guava oder Apache Commons. Diese APIs sind viel näher am Entwickleralltag dran und sind in sehr vielen Projekten eingebunden. Und Oracle macht seit Java 8 auch die eingebauten APIs viel entwicklerfreundlicher.

cdonat schrieb am 09.10.2019 15:43:

Ein Beispiel, wenn man drei Matrizen multiplizieren möchte:

C++ mit den meisten Matrix-Libraries:

auto result = matrix_a * matrix_b * matrix_c;

Das beste, was ich wüsste, wie man es in Java herbekommen kann:

Matrix result = matrix_a.dot(matrix_b).dot(matrix_c);

Ja, dieser Fall ist mit der Multiplikation sehr viel verständlicher, ja.

cdonat schrieb am 09.10.2019 15:43:

Sehr elaboriert, weniger leicht zu verstehen und noch dazu geradezu zwangsläufig langsamer, weil die Grösse der Ergebnismatrix erst zur Laufzeit festgestellt wird, während die C++-Lösung sie aus den Typen von matrix_a, matrix_b und matrix_c selber herleitet. Die C++-Lösung prüft auch zur Compilezeit, ob die drei Matrizen überhaupt kompatibel sind, so dass sie in dieser Form multipliziert werden können. Auch das macht die Java-Lösung erst zur Laufzeit.
[/code]

Ne, Java prüft sowas idR. auch beim Kompilieren ob es vom Datentyp her passt. Oder ich habe diesen Abschnitt nicht verstanden. :/

cdonat schrieb am 09.10.2019 15:43:

Wenn ich da was über die API herausfinden möchte, lande ich auf JavaDoc-Seiten, statt auf Tutorials, die einem die Sicht des API-Users in seinem Code zeigen würden :-(

Aus dem Guava-Tutorial:

Joiner joiner = Joiner.on("; "); return joiner.join("Harry", null, "Ron", "Hermione");

versus in Python:

return "; ".join(("Harry", None, "Ron", "Hermione"))

Da ist die Java-Variante schon für so was simples sehr geschwätzig. In C++ ist das derzeit noch ein PITA, aber ich hab schon mal eine Library in der Mache, die das dann so aussehen lassen wird:

Man kann es auch so schreiben:

return Joiner.on("; ").join("Harry", null, "Ron", "Hermione");

MfG

Bewerten
- +
Anzeige