Last active
May 7, 2024 10:55
-
-
Save milleniumbug/3bd74fcdce6355d1355f05cec1a909b2 to your computer and use it in GitHub Desktop.
why Java sucks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Let's start with: Java is a language that one would create when looking at the state of C++ in early 90's and thinking how can I make it "better" in terms of being error prone. | |
But this was only an evolution instead of a revolution STL introduced as a way of programming | |
(sure, they weren't first, but I'd say they were the first to introduce it to masses) | |
The rest is a consequence of being backward | |
Problem with null pointers? Still there | |
Speaking of pointers in Java, I like how Java fans continuously say "they're not pointers, they're references" | |
But guess what happens when you access a null reference? A NullPointerException is thrown | |
So what I don't like? | |
Collections API. Just terrible. | |
The "unmodifiable" lists are your regular lists that throw exceptions on modifications | |
DON'T PROVIDE THESE OPERATIONS IN THE FIRST PLACE FFS | |
but that would mean actually designing your class hierarchy instead of doing something similar to "Animal - Mammal - Dog" examples | |
Also there's List.get(int index) method | |
and both ArrayList and LinkedList implement List | |
for the latter it actually means traversing the list until the element of this index is found | |
Sure you can check whether the List is an instance of a tag interface RandomAccess | |
BUT WHY DO YOU PROVIDE IT IN THE FIRST PLACE | |
let it be a method in RandomAccess | |
oh wait you can't actually say "this variable is both a List and RandomAccess" so you have to make all these auxiliary classes | |
...actually, no, you actually can do this for function parameters, thanks to generics | |
so this can't be the reason. | |
this is when you notice you're in a deep hole of helplessness | |
There's no type deduction of variables (like C++ auto or C# var). Fixed in Java 10, they introduced var. | |
so you have to write MyLongClassNameClass x = new MyLongClassNameClass(arguments); // FML | |
There's "diamond operator" in Java 7 which helps a bit for generics | |
so you can write Map<String, Integer> m = new HashMap<>(); | |
instead of Map<String, Integer> m = new HashMap<String, Integer>(); | |
Oh, regarding generics | |
Only reference types can be passed as a generic | |
So in Java 8 you have Stream<T>, IntStream, DoubleStream, LongStream, Optional<T>, OptionalInt, OptionalDouble, OptionalLong | |
there's only three of the "special" classes, so I guess they thought writing these for all 8 of primitive types was too annoying | |
Arrays are covariant, which is terrible | |
(this means Dog[] is convertible to Animal[]) | |
but this introduces type safety violations because you can assign a Cat to what should be Animal[] and what would be a compiler error is now a runtime error | |
(there's code which is ran on assignment that checks whether the dynamic type is correct) | |
...the same problem exists in C#, but there you can get away with not using arrays quite far (see above remark about generics and notice it doesn't apply to C#) | |
I've already mentioned null pointers? Yeah, they're a problem | |
The current stance on null pointers among Java programmers is: don't | |
Another problem is lack of operator overloading | |
Have fun writing BigInteger a = new BigInteger("2364564564564645645"); BigInteger b = BigInteger.valueOf(2); BigInteger c = BigInteger.valueOf(3); BigInteger d = b.multiply(a.add(c)); | |
Also, checked exceptions | |
They're a total pain in Java | |
Both the fact they're completely abused in standard library | |
and the fact you can't handle them in generic scenarios | |
You have some kind of visitor that visits some kind of a data structure? Have fun writing it without kludges or declaring the function as throws Exception, which means now more code has to catch exceptions which will never happen | |
(also you can't generically declare that a function throws an exception when some another function does) | |
this sums it up | |
https://twitter.com/mariofusco/status/739698058582196224 | |
There are issues in bad class design all over the place | |
Because of curiosity I looked up how Java does random numbers | |
https://docs.oracle.com/javase/8/docs/api/java/util/Random.html | |
Just look at the setSeed method | |
for now, let's put aside the fact that Random is not an interface | |
...oh, look SecureRandom is a subclass of Random | |
IOW the non-deterministic random generator is a subclass of the deterministic random generator | |
https://docs.oracle.com/javase/8/docs/api/java/security/SecureRandom.html#setSeed-long- | |
clearly says it violates the contract of setSeed | |
...well of course | |
there's no other option than to violate the contract with such class design | |
Liskov Substitution Principle is violated all over the place | |
and Cloneable is a tag interface | |
fucking retarded | |
(by "tag interface" I refer to interfaces which have no methods, so the only operation you can do is x instanceof TheInterface) | |
so if you have a list of Cloneables, you can't clone them because the .clone method isn't a method of Cloneable | |
Another problem is auto-unboxing of the "reference types wrapping primitive types" | |
like: byte -> Byte, char -> Character, int -> Integer and so on | |
conditional operator ?: normally does conversion to a "common type" in all languages where it exists | |
but in Java true ? 5 : (Integer)null throws a NullPointerException (!) | |
because instead of converting the 5 from int to Integer, it converts (Integer)null to int | |
which, as expected, is a lossy conversion | |
because we're mapping {null} ∪ [Integer.MIN_VALUE, Integer.MAX_VALUE] to [Integer.MIN_VALUE, Integer.MAX_VALUE] instead of doing the reverse | |
I can't explain this in another way than "someone was drunk that day" | |
You know what is fun? URL class doing DNS lookup in an equals method | |
this means the answer is different whether you're connected to the internet or not (!) | |
god forbid if you're using them in a hash table |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
yo... I love this rant! Java is f*cking retarded and soo verbose. The new streams API is an abomination; shoving something in because its fashionable but does not have the syntax that makes using the programming technique efficient or clear. A small amount of clever coding you can do groupbys with comparators and for loops treemap. Anyway... I enjoyed this.