views:

3856

answers:

45

I read a lot of blogs and see people all the time talking about bad things in the java programming language; a lot of them are about annotations and generics that were added to the language in 1.5 release. What are the things in the language or the API that you don't like or would design differently?

+16  A: 

Primitive types (ints etc.) are not objects like in Smalltalk, forcing the programmer to use boxing classes such as Integer.

Smalltalk integers are real objects. In order to avoid overhead, they are not implemented as "boxed" primitives, like Java does, but instead as "immediate" objects: the object's value is stored within the object "pointer" (the same is true with individual characters) To do so, it uses the pointers' low bits, which are always zero for regular objects (since structures are usually word-aligned), as "tags" to differentiate immediate objects with the former. For example, if a pointer's bit 0 is set, it designates a SmallInteger object: its integer value is stored in the remaining 31 bits. Larger integers use regular objects with infinite precision (AKA bigint).

Java 5's autoboxing is the worst of all solutions, because it hides the overhead behind syntactic sugar: the programmer is unaware of the fact that objects are created behind his back although he's using primitives. Not only that, but several Integer objects could be created for the same int value. Whereas in Smalltalk, the value IS the objects. This also allows the compiler to generate optimal code, in a way that can't be done with boxed objects. Smalltalk proves that primitive types can be objects AND be implemented efficiently.

This is one of the reasons why Java cannot be considered a high level language (not that this can be a problem or drawback in any way, there is ample room for system level programming languages).

fbonnet
Interesting, that's something that I *like* about Java! :-)
Brian Knoblauch
Primitives also don't have the memory / computational overheads that Objects do. If anything, primitives are a feature.
Richie_W
Also, since Java 5.0 there's autoboxing
João da Silva
@Richie_W: first-class primitive objects don't have to be heavy. See Smalltalk or Lisp for examples, where they are implemented as immediate values (for example, storing the integer value within the pointer). This is the reason why Java cannot be considered high level.
fbonnet
@João da Silva : sure but this is just sugar - the JVM still makes the distinction. So autoboxing adds overhead behind the programmer's back.
fbonnet
fbonnet: how could there not be overhead? Do you think integers in Smalltalk (or any other OO language that can reat an integer as an object) adds no overhead? How would they do that?
j_random_hacker
@j_random_hacker: see my edited answer for more info about Smalltalk's immediate objects.
fbonnet
I won't mark you down because you definitely thought out your answer, but everything you just said they got wrong is things I believe they got right. - Except leaving out auto-boxing, which they later fixed. :o
280Z28
what evidence do you have that the auto-boxing brings overhead ? Can you objectively quantify this overhead and give example of where it is detrimental to the program when compared to using objects all the way ? Other than the few more keystrokes how different is it when using Integer objects in Java directly vs smalltalk objects primitives ?
Newtopian
I have never seen autoboxing take a significant percentage of CPU time in code I've profiled.
finnw
@fbonnet: Your edit was helpful so I've dropped my -1. But I'm with 280Z28, I still feel that the autoboxing-with-full-size-primitive-datatypes approach is cleaner, and I would expect faster (since with Smalltalk's "hybrid" representation, every arithmetic operation must need a pre-right-shift and post-left-shift, no?)
j_random_hacker
+2  A: 

I tend to get a little irked by the deprecation of good useful objects and their replacement with ugly, hard to use objects (example: Date & Calendar).

Brian Knoblauch
Date was not "good useful", it was "simple and broken".
Michael Borgwardt
I would be completely okay if they added JODA to the java API.
BlueRaja - Danny Pflughoeft
+22  A: 

On the java platform: AWT, and the XML APIs (it's amazing what you have to do just to parse a String into a DOM tree)

On the language: add type inference and tuples, generics without erasure, make 'volatile', 'strictfp' and 'transient' annotations

João da Silva
the XML api is such a load of horse hooey!
nes1983
If you've got to deal with hooey, wouldn't you want great (long) tools to deal with it?
Tom Hawtin - tackline
volatile and strictfp change the semantics, so aren't really suitable to be annotations.
Tom Hawtin - tackline
+1 for XML APIs. The whole XML stack in Java is a mess, especially the lower parts of stack.
Domchi
+1 for AWT and XML APIs. Many things get a lot easier when using wholly separate XML tools (e.g. dom4j).
Jonik
Quite frankly, I have yet to see any language do XML really well. It's not surprising since it's quite complicated compared to a lot of other markup languages (such as JSON) IMO.
Tom
Gotta love this criticism of the XML APIs by Joshua Bloch: http://www.youtube.com/watch?v=aAb7hSCtvGw#t=46m02s :)
Jonik
Make `native` an annotation too. I also prefer JNA's access of native functions to JNI
KitsuneYMG
+22  A: 

I think the Java language is overall well designed. I just think it's way too verbose.

MiniQuark
The verbosity and rigidity is what make it maintainable as it is READABLE! You are encouraged to be verbose by the example of the runtime library.
Thorbjørn Ravn Andersen
I don't like the huge long lines either, but I agree with Thorbjorn, it often does aid readability.
TM
VB is a verbose language also. That doesn't make it any better than, a less verbose one. What's wrong with ":" instead of "extends", it's perfectly readable, when you see "class Derived: Base", to think "class Derived extends Base". conciseness.equals(readability) or conciseness == readability ?
Pop Catalin
The important thing is clarity. *THEN* comes conciseness. C++ = concise -)
MiniQuark
C++ is not what I'd call concise. (C++ is naturally obfuscated) I can't say I saw a C++ program that was concise, actually C++ is notorious for the length of it's programs compared to other languages.
Pop Catalin
You're right. I was thinking about expressions like f(a++) which are very short but can actually do a lot a things under the hood, such as calling a copy constructor, call a cast operator, etc. But "obfuscated" is a better word for what *that* is!
MiniQuark
I think this is mostly a moot point: when reading code, readability is of paramount importance, as others said, and when writing code (as a 'serious' programmer, anyway) you naturally use a good IDE, which autocompletes and fills in everything mundane for you.
Jonik
How can you say Python is clear? I've seen the most awkward expressions in Python...
Aviad Ben Dov
Java: The OOness of C++ with the verboseness of COBOL.
Slapout
@Pop Catalin : what is wrong with ":" instead of "extends" is that extends really means what's happening. If I'm a beginner and I see ":", I can't really know what it means
Valentin Rocher
@Bishiboosh " If I'm a beginner and I see ":", I can't really know what it means". If you're "true" a beginner then the chances are you don't know what extends means ... but once you know what : after class name means (which is one of the first things you learn), dot syntax helps create more readable code (because identifiers are more visible have higher text reading weight). Of course the trick is to not over do it.
Pop Catalin
A: 

Bundling .jar files: 1st: .jar files don't really have icons (wtf?!), then you cannot include .jars in .jars (omgwtffff). Together: write your code once, run it anywhere and write a 6-page manual for every platform on how to properly bring your UI up. Include sentences like: "we recommend setting the classpath. to do that, run msconfig in a shell"

Make a contract with the nearest suicide aids provider.

nes1983
It's become a bit better when we the have the webstart, JNLP.
Dennis Cheung
Or an installer.
Tom Hawtin - tackline
-1. jar files not having icons is a really really bad thing... lol
Martinho Fernandes
-1 For kewld00d talk and "lack of icons".
Jan Jungnickel
+6  A: 

JNI could be one of the worst in Java.

It is much much more time wasting if you compare it with PInvoke in .NET.

Dennis Cheung
Yes, it's much easier to be better with 7 years of hindsight.
Software Monkey
But then again the ease of P/Invoke lead to many .NET applications not being able to run on pure .NET but depend on Win32 instead (= no chance for Mono).
Joachim Sauer
It should be a decision of the programmer. Not the platform provider.Anyway, I hope mono will able run them some day later, think about WINE.
Dennis Cheung
I'm glad it's not easy to tie java apps to a specific platform. Doing it would destroy the whole purpose of java.
RommeDeSerieux
+1. I actually find it easier (on Windows) to write a C# library to access the native functions via P/Invoke, expose an ActiveX object from the C# library then access that from Java using JACOB.
finnw
+50  A: 

I really don't like the manipulation of dates in Java (java.util.Date, java.sql.Timestamp, java.sql.Date, java.util.Calendar).

MiniQuark
I agree. I found a link today about it, I paste it here: http://stackoverflow.com/questions/214289/what-new-features-in-java-7-do-you-find-most-useful#460101 The fix is coming in Java 7 ( hopefully )
OscarRyz
Fanstastic. They deprecate the Date functions, replace them with the Calendar. Now they are looking to fix that replacement. Third time's a charm?
daub815
Calendar was a halfbaked package inherited from Taglient. I believe Sun learned quite a bit from that.
Thorbjørn Ravn Andersen
Java dates suck. Calendar sucks too. At my place of work we wrote our own wrapper to simplify the usage, but it still sucks. I feel that Java's date system is the worst of any language I've used.
TM
All the Java date/time APIs are complete trainwrecks. I really don't understand how they could create something that bad. Hire a 3rd year university co-op and they'd do a better job.
Matt Olenik
JodaTime anyone? It's not perfect, but pretty damned close compared to the Java Date / Calendar api!
Kimble
Absolutely. The calendar class is based on the idea of one of those flipping desktop calendars, and it's wrong, wrong, wrong. It was done in the early days of OO programming. Timezones are a continuous nightmare. JDBC in particular needs a way to pull back a date as a Calendar object. Oh - and it's the wrong word, too.
paulmurray
+8  A: 

No destructor. I wish there was a standard (optional) way to say "I'm done with this, run some code", rather than relying on the finalize method that may never get called. I'm not talking about having to manage memory, just that when you do want to finish with something, there was a standard call to make which would do whatever clean up you wanted and then provide (maybe) some hint to the Garbage Collector that you're done with it. I'm sick of having some classes with a "close" method, and some with a "done" method, and so on and so forth.

Paul Tomblin
There is a way to do this - have some other class call myObject.cleanUp() (or whatever) just before you release the last reference to the object. You're right that finalizers should be avoided as they're not a good idiom at all.
Andrzej Doyle
There is a much better and more controllable way to handle it than destructors, look into references (weak reference, ...)
Bill K
Agreed, doing things when leaving a scope is a really powerful concept even if it's not related to memory management. Scoped benchmarks, locks etc is great.
Laserallan
Finalize is NOT meant for replacing destructors.
Mnementh
RAII would solve this.
Bernard
If there isn't one already, make an `IDisposable` interface and implement it on the relevant objects. Even without syntactic sugar like a `using` statement (C#), *everyone* will know what it means when you implement that interface and you won't me fighting with what to call the `Dispose` method (`dispose()` in Java?).
280Z28
Java 7 http://tech.puredanger.com/java7/#resourceblock uses `Closeable` to indicate automatic resource management
KitsuneYMG
+54  A: 
  • Checked exceptions.
  • Every object Is a monitor.
  • Primitives are not objects.
  • Lack of properties.
  • The way generics are implemented.
dalle
+1 especially for checked exceptions. They could have worked as a hack to get around the inconvenience of returning various types of structured values from functions, but the standard class library uses them for all kinds of annoying and inappropriate purposes. Foul!
bobince
Checked exceptions are fine when used correctly.
Dan Dyer
Except not all exceptions are checked. NullReferenceException, anyone? The jury is still out on whether checked exceptions provide real value, given the ammount of exception-translation work it requires to use correctly.
Aaron
I believe that the argument for checked versus unchecked is that checked exceptions represent something that the program should be able to correct, while unchecked aren't. Of course, there are a lot of exceptions (sorry) to that rule, particularly in javax.xml.
kdgregory
@dalle - it's a nice list, but would you care to provide justification for any of them?
kdgregory
@kdgregory They're generally right. Look around some answers here for details. I can live without properties though, they just encourage the property pattern which, while not ALWAYS terrible, tends to break encapsulation pretty severely.
Bill K
@BillK - and for each of them you can find arguments on the other side. Personally, I'd like to hear a good justification of why primitives are bad; heck, _any_ justification other than "everything should be an object" or "I have to box to use a Collection" would be nice
kdgregory
checked exceptions are great since you need to think about what should be done. The ability to wrap in a runtimeexception can make any checked exception unchecked!
Thorbjørn Ravn Andersen
And the way arrays are not (a) really objects, and (b) not easily resized.
Software Monkey
GOD I had java generics. I feel like they are stapled onto Java
Simucal
arrays most certainly ARE really objects. They have a constructor, fields, methods, everything. They get some syntactic sugar and special JVM treatment, that's all. And OF COURSE they're not resizable - that's what ArrayList is for.
Michael Borgwardt
Checked exceptions are great. Problematic in Java are the runtime-exceptions (the not checked exceptions).
Mnementh
I like checked exceptions too. They can be misused but at least they are explicit.
Mr. Shiny and New
Quote from Satya Komatineni's Blog: "Interfaces and checked exceptions are like butter and sand: they don't mix well"
dalle
The fact primitives are not object is a necessity for performance and interoperability.<BR>The lack of properties is annoying.
Danny Varod
Checked exceptions are horrible. What a great way to cause simple changes to create a cascade of modifications to other classes, and to add a lot of worthless code. Every time I catch an exception only to throw it again (or a different one, or to log it and toss it out), I feel sad.
TM
@Danny: Not quite a NECESSITY. It's a quick and fast route to get performance and interoperability. But not the only (and not certainly the best) way.
Martinho Fernandes
I like the fact they primitives are not objects and that it does not have properties.
Johannes Schaub - litb
Primitives are by definition not objects! They're primitive for performance reasons. The only place this ever runs into problems for me is when you can't use primitives in a place where space/time performance reasons are important. (e.g. ArrayList<int> not allowed but would have been nice)
Jason S
I hate using get... and set... methods. I don't know why, particularly, but, there you go!
Lucas Jones
I disagree with everything above.
GreenieMeanie
@GreenieMeanie: Thoughtful and well put *chokes on sarcasm*
Ed Swangren
-1 for properties. Nobody has been able to tell me what's wrong with using public attributes instead ( if what they want to avoid is not to type get/set ) The most common answer is "because you could probably add logic to the property ( hence making it a method )
OscarRyz
@simucal, that's because they *WERE* stapled onto Java, in like Java 5...
Brian Postow
About primitives. They don't have to be implemented as objects under the hood, but it would be nice if they could be used like objects in the source. Ruby does this well `1.upto(10)` for example. With auto-boxing, the worst things about using primitives have been fixed.
KitsuneYMG
@Oscar: The most common answer is precisely the right one. In Python for example, you may want to define a public variable. If later you decide it should have some code in the getter and/or setter, you can make it into a property without changing the external interface. You could always use getter and setter methods for everything, but properties are cleaner.
Javier Badia
+36  A: 

generics-as-afterthought

Jason S
As opposed to never shipped because were still trying to get generics right when the project was cancelled?
Tom Hawtin - tackline
Java's generics piss me the hell off.
Daddy Warbox
C#'s generics are also an afterthought really. They only appeared in what version 3?
Robert Gould
Version 2.0 to be exact. But .NET generics are properly implemented at runtime. Unlike Java generics where Sun was too scared, under vendor pressure, to change the IL to support generics. So you end up with a half assed implementation that has things like "type erasure".
Strelok
2.0 feels almost like a complete rewrite of 1.1 anyway
annakata
The .NET generics work great, except that it caused all code that used non-generics to be "out-of-date", and then when changed to generics caused all the code that uses it to not-compile... At least in Java, with all the problems erasure gives, libraries are still backward compatible... And they give themselves the option to implement it differently later on, when enough people leave JDK 1.4.
Aviad Ben Dov
+20  A: 

Ever since I have learned python, I just find that Java lacks the possibility of returning multiple values easily:

#In python:
name, age = john.summary()

//In Java:
Object[] summary = john.summary();
String name = (String) summary[0];
int age = ((Integer) summary[1]).intValue(); #primitive types require boxing

Edit: as mmyers pointed out, the following is legal as of Java 5:

int age = (Integer) summary[1];
MiniQuark
This particular issue is currently being discussed here: http://stackoverflow.com/questions/457775/does-java-need-tuples#457809
Dan Dyer
Something that bothered me at first, but I've since decided that it's a good thing. Forces one to spend the extra time to encapsulate complex returns.
Brian Knoblauch
The problem being that because Java doesn't support value typed structures or by-reference arguments, returning multiple values means a heap allocation on every call. Garbage collection is pretty good, but it's still a waste to do that.
U62
Agree with @Brian (and virtually all arguments are by reference/stack, @RHM)
Bill K
Agree with Brian.
Software Monkey
I don't like the Java here. Way too hard to read compared to the Python.
Nosredna
I should point out that the intValue call is not actually necessary. "int age = (Integer) summary[1];" is perfectly legal as of Java 5.
Michael Myers
That happens when you try to use a Python idiom (I know it's used elsewhere as well) that's not "native" to Java: it won't look nice.
Joachim Sauer
@mmyers: Worthy to note that behind the scenes, it will call intValue().
Aviad Ben Dov
+10  A: 

Keeping too much C syntax that was known to be problematic. The switch statement should have been redone for Java. Operator precedence is at least a more complicated problem; while Java could do better than C there was some advantage in keeping it.

One goal for C++ was to be at least a better C, and so Stroustrup had an excuse for keeping bad C decisions. Gosling et al. didn't.

Edit: Also octal literals (thanks, Dan Dyer, for pointing that out). Those are very useful things for writing OS internals and bit-grovelling code, which are applications Java isn't usually used for.

David Thornley
I agree. Fall-through in switch statements is an invitation to write buggy code. Also, do we really need Octal literals?
Dan Dyer
I could go for a re-write of switch. I definitely would NOT throw it out like others would. It has a place, just perhaps not as frequently as some like to use it.
Brian Knoblauch
A switch statement is useful, and making one that's better than the C version that Java uses is not hard at all. Octal literals are another thing (thanks, Dan) that are better suited for C than Java; I'd just get rid of those.
David Thornley
C# allows switch on strings and doesn't fallthrough...
FlySwat
One reason for keeping C syntax was so that developers could easily switch from C/C++ to Java. I think that's a pretty good excuse, because without programmers, a language dies.
Mongoose
C#'s switch is still broken. It can't do ranges and you have to put in break statements. They should have used VB's Select Case as a model.
Jonathan Allen
You don't need break statements Jonathan.
FlySwat
I think you do. Either return, throw or break.
Martinho Fernandes
Yes, you do need break statements.
Ed Swangren
I thought you were blaming someone named Dan Dyer for making sure octal literals made it in. :o Also, I think Java/C# have potential as languages for low-level target applications and decisions that hurt those targets should, at the least, not be taken so lightly.
280Z28
@280Z28: Edited to clarify about Dan Dyer, thanks. I'm not sure about Java and C# as low-level languages: how are they at taking raw bytes and making data structures out of them? A low-level language simply has to have ways to bypass the type system. Even so, removing the C-type octal notation will help things a lot more than it will hurt things.
David Thornley
C# cases *can* fall through. There's a special syntax for it: "`goto case B;`"
finnw
+8  A: 
  • The default access mode should be private.
  • Bytes should be unsigned.
  • The Cloneable interface should include the clone() method.
Dan Dyer
Bytes shouldn't have autocast to ints (therefore no arithmeic, therefore no signed vs unsigned). Cloneable should not have been. Default private outerclasses and methods is probably over the top.
Tom Hawtin - tackline
IMHO, It doesn't make much difference whether bytes are signed or not. However the range 0 - 255 is more useful than the range -128 to 127.
Peter Lawrey
Heck, I'd be happy if ALL variable access was private too!
Bill K
+2  A: 

A couple of years ago I appreciated Java more than I do today.

I fell deeply in love with their packaging. Today I despise it. A gazillion classes all over the place packaged in a way that would have very little sense hadn't you had experience armed with you. Check out the language ref for AS3 and see what I mean. The 2nd day I started working in AS3 I wasn't going on google looking for tutorials on how to do something, I was already a natural, knowing instantly where that class that I never knew even existed, that did exactly what I needed, was located.

Java still has a great community, but it's not as intuitive getting involved in their communities as it is with other languages. Other languages have provided way better developer portals, way better and more resources.

Basically, Java got too big to handle, got big before they'd lain out everything for its growth. It's too bogged, too confusing. They used to be the forward thinkers in so many aspects, now they are good in few and in some we just wish Java would collapse once and for all.

kRON
A: 

[Hmmm... not sure why the downvotes...]

Java should not have used the same syntax as C++ with different semantics.

A couple of examples

  • meaning of "protected" is different

    • C++: "me and my subclass"
    • Java: "me, my subclass, and my package"
  • meaning of "Dog d" is different

    • C++: "d is an instance of Dog"
    • Java: "d is a POINTER to a Dog"

This causes a great deal of confusion with C++ folks who learn Java. I still see many people shocked when they hear that "protected" includes other elements in the same package...

(If you don't think Java has pointers, see http://javadude.com/articles/passbyvalue.htm)

Scott Stanchfield
I'd like to point out that the downvotes you are getting is not because you said "Java has pointers" (Though pointers and references are not the same), but because we see the two things you pointed out as good things.
FlySwat
Keeping bad habbits from C++ would be a huge mistake. C/C++ programmer can not expect all other languages to be compatible to them. Even C++ is being changed to remove many of its old mistakes (look up C++Ox).
Danny Varod
The "Dog d" convention for d being a reference to a Dog is used in many languages. The fact that all objects can be by value, reference or pointer in C++ can be very confusing.
Danny Varod
My point isn't that these are good things that Java missed; my point is that Java uses the same syntax as C++ to mean different things...
Scott Stanchfield
I agree on the naming schema @Scott
WolfmanDragon
+5  A: 
  • Fields, parameters and local variables should be final by default and only mutable when set. e.g. var
  • There is no consistent way to make an object immutable. (Only references and primitives)
  • wait(long timeout, int nanos) on every object, even though it does not have nano-second precision and probably never will.
  • Object.getClass() returns Class<?> i.e. getClass() doesn't know what class it is at compile time. e.g new Integer(0).getClass() in code returns a Class<?> not Class<Integer> however when you compile the code it returns Class<? extends Integer>, thank you @Mr. Shiny and New
  • array types don't override toString() as so print something like "[B@ef172a" However, Arrays.toString(byte[]) would be a useful default behaviour.
  • Integer.class.isAssignableFrom(int.class) == false. int.class.isAssignableFrom(Integer.class) == false. Yet with autoboxing and reflections there is very few examples where this is the case.
  • @Deprecated are never removed, even if it has been deprecated since version 1.0.x
Peter Lawrey
Class<? extends Integer> c = new Integer(0).getClass(); compiles for me.
Mr. Shiny and New
*"Fields, parameters and local variables should be final by default"* - Eh? I've always followed "make the common case the default," and that is not the common case by a longshot.
BlueRaja - Danny Pflughoeft
It is not the common case because that is how people have learnt to program. If you get used to using immutable objects, that becomes the common case. Immutable objects have many advantages over using mutable objects which too many developers just haven't ever thought about (which is why I would prefer immutable to be the default)
Peter Lawrey
For example, many of the built in data types such as wrappers are immutable and the ones which are not are clearly labelled Atomic or the like. Date is mutable, but most people assume its immutable. This only works because people treat Date as if it were immutable.
Peter Lawrey
It is easy to label an immutable field as the default and there not mutable. And it works until someone changes the code assuming the field is mutable, but you have assume the value won't ever change once set. Basically, there is no way to know if a field unmarked is safe to change without reading all the code. If it were specifically labelled mutable, you would know it safe.
Peter Lawrey
+7  A: 

No destructors, therefore no possibility of RAII.

Most objects are memory-only, which Java's GC handles just fine. But whenever you have a class that allocates non-memory resources (e.g. DB handles), you need to remember to clean it up in a finally block every time you create an instance -- so you need finally blocks everywhere containing the same cleanup code, and if you forget one place, bang, resource leak as soon as an exception is thrown in that scope.

This is one of the (few?) things C++ got right -- you write the cleanup code just once in a destructor, and the language guarantees that it will always be called when an instance of that class goes out of scope, even in the event of an exception. I realise that Java is GC-collected, but RAII and GC are not mutually exclusive -- there just needs to be a way to specify deterministic destruction at scope exit for a particular class or instance, and to provide a destructor. Really, you would not believe how much this simplifies resource management.

It's been 5 years since I touched Java, maybe this has changed?

j_random_hacker
So Java doesn't have the IDisposable / Using pattern that C# does?
FlySwat
Weak References can do the exact same thing as destructors, but in a much more controlled way. There is a collection with the explicit duty of calling destructors as an object is being GC'd--this stuff has been in there YEARS now and I still hear "no destructors"
Bill K
Bill K: Could you say what collection that is? I googled for "Java RAII", "Java deterministic destruction" and "Java Dispose pattern" and couldn't find anything (except people complaining that Java doesn't have it...)
j_random_hacker
@Bill K: There are no deterministic destructors in the C++ style. Finalizers in Java/C# shouldn't be used in the same way that they are in C++ - they're more a "last line of defence" than "the normal way of cleaning up."
Jon Skeet
@jon Skeet Yes, that's why I suggested references. @j_random Look at the reference queue and weak/phantom references (Also look at WeakHashMap for smart caches). Here is a whitepaper: http://www.ibm.com/developerworks/java/library/j-refs/
Bill K
@Bill K: Thanks for the link. Useful classes, but they just prevent unnecessary elongation of an object's lifetime, they don't guarantee finalization. I quote: "Therefore, the bottom line is that you can never guarantee that an available object will ever be collected by the garbage collector."
j_random_hacker
RAII is incredibly useful and Java cannot support it. Using finally is not a scalable solution and it must be done explicitly in the implementation which increases the risk of programmer error.
Bernard
+1  A: 

I'm by no means an authority for what Java is doing wrong, but from this rant on comp.lang.lisp it looks like there is logic error in their exception handling. Is that a fair assertion?

asdfqwer
I think that rant's claims about losing the exception stack are exaggerated. Other than that, it seems to me the approach attributed to Lisp greatly complicates exception handling (it adds power, sure, but it greatly complicates it). For example, the article postulates that you could write code that the decides to resume on an exception 30 frames and two libraries deeper than your code ever contemplated. Sounds bad. Sure another exception will happen, but it sounds like a bug waiting to happen.
Yishai
A: 

In two words: Turing Tarpit.

Ant P.
Why is Java a Turing tarpit?
Martinho Fernandes
There's a few good reasons at the top of the page. My own specific gripe is that it requires a disproportionately huge amount of boilerplate code. It's improving, I still find it far too long-winded to be productive in.
Ant P.
@Ant: You've obviously never programmed in C or Assembler.
Software Monkey
+9  A: 

Too much focus on simplicity at the expense of expressiveness. That basically sums it up.

dsimcha
+12  A: 

The test-unfriendly servlet API... you need a framework to be able to mock a bloody Request!

Germán
+14  A: 

All References are nullable

All references are nullable, which causes a lot of NullReferenceExceptions. I think something like "Option" (Scala) is better suited for those rare cases where an object reference actually should be able to be "Nothing". Of course that would have required Generics and some Pattern Matching right from Version 1.

Lemmy
I'm currently trying to compare the pros/cons of Code Contracts vs. Spec# as a way to correct this issue in C#.
280Z28
Shouldn't that be "References are nullable"? Since an Object can't be null.
Joachim Sauer
true true...fixed it
Lemmy
A: 

Non-resizeable arrays. Yes I know you can allocate another array and System.arraycopy() the original... but would it have been so hard to have, e.g., array.resizeTo(x), array.growBy() and array.shrinkBy().

And no way to make an array entirely final (it's reference and all of it's elements).

Edit: Arrays don't implement the Collection or List interfaces.

Software Monkey
You have ArrayList for that.
Martinho Fernandes
@Martinho: Get serious :)
Software Monkey
what's wrong with ArrayList ? what can a simple array do that ArrayList cannot ?
Newtopian
@Newtopian: Ummm, store primitive values without boxing overhead?
Software Monkey
+9  A: 

Checked exceptions are a problem in Java because they may break encapsulation.

There is an interview worth reading with Anders Hejlsberg on Artima where he talks about that:

Anders Hejlsberg: Let's start with versioning, because the issues are pretty easy to see there. Let's say I create a method foo that declares it throws exceptions A, B, and C. In version two of foo, I want to add a bunch of features, and now foo might throw exception D. It is a breaking change for me to add D to the throws clause of that method, because existing caller of that method will almost certainly not handle that exception.

And if you used unchecked exceptions the caller WOULD handle it? This isn't "breaking encapsulation" but rather "changing your api contract".
Mr. Shiny and New
The point is that exceptions thrown by a method should not be part of the API contract, any more than the methods it calls, or the algorithms it uses.
John Saunders
In my opinion the problem with the quote above is misuse of the exception. It you have a method that does-everything-and-anything the problem is not with the exceptions but with the overcomplicated method itself. The added features would most likely be better in another new method and changes are no longer breaking. You are correct in saying that interface contract does not depend on the implementation of this interface. However failure to do the action IS and MUST be part of the contract and checked exception is a great way to ensure failure are correctly propagated to client code.
Newtopian
Most complains of the sort I have seen involve examples where foo would let exception thrown from the methods it calls as part of it's implementation, and as such people want unchecked exceptions so they do not have to bother with exception handling at all. To me unchecked exception that simply fall through and checked exception stacking on method declaration are both a good example of conceptual bleed where your interface fails to capture the complete behavior of the system it tries to abstract. Checked exceptions is, so far, the only way I know to ensure the API contract is complete
Newtopian
+18  A: 

Arrays are covariant which shouldn't be.

See: Wikipedia Article

FA
Why is this so highly ranked? Yes covariance of arrays has caused me problems... Once. In 11 years of Java coding.
finnw
This should be higher ranked in my opinion
BlueRaja - Danny Pflughoeft
+1  A: 
  1. Variables should have been not nullable by default.
  2. Fields and variables should have been final by default.
  3. There ought to have been a type for method references (first-class functions).
  4. Missing the ability to seal types (not classes, but types).
  5. Inability to do case-analysis on complex types (enumerations only, sorry).
Apocalisp
You're wrong about being unable to seal types - that's what final does as a class modifier.
Software Monkey
But oh so right about first-class functions.
Software Monkey
It's true that you can mark a class final to say "this type has no subtypes", but what you can't do is say "this type has these three subtypes and no others". I.e. you can seal individual classes, but not entire types.
Apocalisp
There is the zero-one-infinity rule. No three subtype case.
Martinho Fernandes
I wonder how you enforce the "one" case.
Apocalisp
@Apocalisp: A type cannot be sub-typed if it has only private constructors unless those sub-types are nested in the super-type. You can exploit this feature of Java to (sort of) seal the types.
missingfaktor
A: 

The collection hierarchy in the standard library is completely broken as designed. Just as an example, the List interface has 25 methods that you have to implement, and most of them mutate the list. Collections rely on the elements implementing equals and hashCode properly, which must be done by inheritance, which disfavours composition as a design strategy if you want your libraries to work with the standard library.

Apocalisp
To implement your own collection you can derive from AbstractList, which reduces the number of methods to implement greatly.
hstoerr
I don't understand your comment about implementing equals and hashCode by inheritance. What do you mean with "by inheritance"?
hstoerr
AbstractList is still designed to be a mutable list. You can write an immutable implementation only by throwing exceptions at runtime on mutation attempts.By "by inheritance" I mean that those methods are meant to be overridden in subclasses. As a design choice, I want to avoid subclassing.
Apocalisp
+3  A: 

In JDBC the java.sql.Date class has no time component. This forces you to use Timestamp, which confuses Oracle when your dates are stored as Oracle DATE values.

Also I'm not crazy about how Java is packaged. It's annoying to have to set up class paths and jar files and don't get me started with EAR files and WAR files. There is room for improvement here.

Mr. Shiny and New
+1  A: 

GC

While GC is incredibly convenient, an unpredictable GC is not suitable for certain applications. One such example would be hard real time systems. In a hard real time system a single unexpected delay can result in mission failure.

Examples of such hard real time system would be: fly by wire systems on a fighter jet, navigation systems on a missile, robotic arms that perform surgery, etc.

Also, getting killed in a real time video game is also a mission failure. You don't want to GC right at the moment the player pressed the "dodge the giant fireball that will kill my character and force me to redo the 20 minute long level," button. That is a very important button. (Although it has been noted that in multi-tasking OS you cannot control the task priority which could easily be worse than a large GC operation.)

Static Polymophism

Ignoring static polymorphism. Static polymorphism could go beyond "C++ like" templates, and it is a very useful optimization. Generics as implemented in Java is still dynamic and it loses that opportunity to eliminate run-time type checking where compile time type checking would is enough. Of course is possible for increased code size to reduce performance more so than dynamic types would. As with all optimizations it should be profiled.

Everything is in a class

Although nit picky, there are times when you just want a function. Currently in Java you must put such functions in a class as a static function. A better solution would be a function in a namespace. While a class can work like a namespace, classes cannot span multiple files and libraries.

Bernard
Java isn't the right tool for programming real-time systems. The argument about GC pausing an app is old; a modern JVM always doing GC, so you don't get long pauses anymore. Besides, if you run that game on an OS like Windows, you don't really have any control over process scheduling, anyway.
Barry Brown
Good point on the process scheduling, I'm still learning about real time systems. Regardless "long pauses" is a relative term, but I do see your point about Java serving a different purpose. For non-real time systems it seems to do a good job.
Bernard
Real time is best done in ADA or C. While Java can run real-time systems, but was not designed for them.
WolfmanDragon
GC certainly isn't a Java language problem, it's an implementation issue, and the GC can be selected independently of the language to handle various uses. Also, there are very serious solutions to the issue for hard real-time system, including IBM's Metronome collector: http://domino.research.ibm.com/comm/research_projects.nsf/pages/metronome.index.html
280Z28
there is no one tool that's perfect for everything. Java for real-time systems is just silly. GC is a really nice idea on the vast majority of java-friendly projects. that may be circular reasoning but there's enough projects that fit that to make it worthwhile IMHO. Polymorphism, OTOH, I agree. They sort of went half-a**ed between fully static C++-like and fully useful ML-style type derivation...
Brian Postow
+2  A: 

I like Java a lot, but mainly two things bug me:

  • No unsigned data types - I find that most of the time, it doesn't make sense for the data I have to be negative. Unsigned is like a form of documentation, and it also happens to double the maximum value.
  • No structs - mainly a performance thing.

Also I think doSomething() looks worse than DoSomething(), but that is merely a coding standard, and not really a problem.

Zifre
Structs are really not any faster than classes: the only difference is that every class-method pushes the `this` pointer onto the stack, and class-instances need to dereference to get the value. If anything, having stack-based instances would increase the performance much more than structs, but even that would be such a small increase it just wouldn't be worth it for the extra syntax/beginner-confusion.
BlueRaja - Danny Pflughoeft
@BlueRaja: Avoiding heap allocations and garbage collections is **very** important when writing heavily parallel multithreaded code. GC overhead will eat you alive there.
dsimcha
+1  A: 

I don't like how collections in Java have a toArray() method that returns an Object[]. It's very difficult to cast between a primitive array and a collection.. You end up doing this:

ArrayList<Integer> list = callSomeWeirdAPIMethod();
Object[] f*ckedArray = list.toArray();
int[] realArray = new int[list.size()];
//...copy elements from f*ckedArray to realArray

where you can't do this:

int[] realArray = (int[]) list.toArray();

or even this:

Integer[] realArray = (Integer[]) list.toArray();
Jason Gin
Integer[] realArray = list.toArray(new Integer[list.size()]);
Dave Ray
Well, of course you can't do that. realArray should be of type float[] ! sheesh. B-)
Brian Postow
+1. But it would be nicer if int[] implemented List<Integer>. ints are already autoboxed as Integers. I don't see why primitive arrays shouldn't be autoboxed in the same way. BTW Google's guava library has `int[] realArray = Ints.toArray(list);`
finnw
The collection classes needed to be broken down into read only versions so we don't throw UnsupporttedOperationExceptions just to get a read only list
KitsuneYMG
+2  A: 
  • No operator overloading
  • No real array literals
  • Primitives are not objects
  • No decent multiple inheritance (I know there are problems, but they are fixable)
  • Too verbose
  • No decent way to declare "variables" constant unless they are primitives (i.e. you can still call 'setBar' on a 'final Foo foo')

Not necessarily things they did wrong, but things that I would have liked:

  • Closures and function pointers
  • Destructors
  • Possibility to return multiple values from a method
Jordi
+1 for operator overloading. Anyone who has ever used BigInteger will agree.
MAK
-1 for operator overloading. Anyone who has ever used C++ will agree.
jdizzle
@jdizzle: Just because a few idiots abuse operator overloading in C++ doesn't make it a bad feature. Also, if Java wanted operator overloading that was less prone to abuse, it could allow overloading of arithmetic and bitwise operators but not assignment and copy construction (where most of the abuse is in C++).
dsimcha
@dsimcha I saw plenty of abuse of the arithmetic operators in C++. If '+' can append strings, why not collections? Think "RecList recList; recList += newRecord;" except there is validation logic in the overloaded operator. Yuck.
Kelly French
@Kelly How does allowing me to do whatever I want with `operator+=(...)` differ from allowing me to do whatever I want with 'append(...)'? Both are arbitrary names for an action. Just because I think I know what `append` does doesn't mean I should skip reading the javadoc for it. The same can be said of `operator+=`
KitsuneYMG
@kts The system I worked on was a nightmare because it combined operator overloading with a liberal use of inheritance which made it devilishly hard to figure out which operator was going to be called at runtime.
Kelly French
@Kelly Wow. I never though someone would use `virtual` operators. Or override non-virtual functions. They deserve death. Possible by shoving iPads into uncomfortable places until they pop.
KitsuneYMG
A: 

There are serious downsides which result in boilerplate patterns:

  • type erasure
  • checked exceptions
  • inflexible catch clause
  • no default arguments constructor
  • JavaBean conventions
  • need for redundant type information
  • no observable collections
  • no covariance

...and so on.

thSoft
Observable collection types are a class library issue. New(ish) versions of the .NET Framework have an `ObservableCollection<T>`, but it's not a C# language feature and doesn't get any syntactic sugar. Is there some aspect of them that you'd like to see in the Java language as opposed to simply implementing them in a (possibly standard) class library?
280Z28
Observable collections *do* exist, in both the standard API and third-party libraries. Example: javax.swing.ListModel
finnw
Thanks for pointing this out, but as far as I see, there is only a rather poor (Vector-backed) implementation of this interface, DefaultListModel. I know that 3rd party libraries exist such as Commons Events or Glazed Lists.
thSoft
+1  A: 

java.nio.Buffer, ByteBuffer, etc. are classes, not interfaces, and have no way of allowing you to wrap anything but arrays of primitive types (byte[] for ByteBuffer) in a Buffer so you can pass the resulting object to a method which uses a Buffer.

Jason S
+1  A: 

No public mutable BigInteger and BigDecimal for more performant compound operations and the way requests for them gets always turned down citing the evilness of mutable objects in multi-threaded application. Please then remove StringBuilder as well!

Using question marks instead of named placeholders in PreparedStatements - who wants to count each question mark all the time to check if everything got assigned?

Inconsistent usage checked/unchecked exceptions in the runtime: Integer.parseInt(String) unchecked, String.getBytes(String) checked.

Sub package cross-dependencies in the runtime: java.lang <-> java.io?

kd304
+2  A: 

Making up a whole new logging api (java.util.logging) to be the new standard was a mistake that annoys me. I have to create a subclass of a Formatter just to get output on only one line! What was wrong with log4j?

Peter Recore
A: 

One thing that bites me regularly is the fallthrough behaviour of the switch statement.

Reading the replies made so far, I notice the almost complete absence of multiple inheritance. It is mentioned only once, but used to be a subject of heated discussion a number of years ago. I'm wondering why this is the case. Do people feel it is not really needed? Do people no longer care?

Jeroen van Bergen
Take a look at this blog post discussing C# for some of the reasons several languages have avoided them: http://blogs.msdn.com/csharpfaq/archive/2004/03/07/85562.aspx
280Z28
A: 

Lack of Class modifier Friend. One long and verbose class can be broken into two Friend-ly Classes in C++, but not in Java. A static inner class will do the same thing as long as the code never needs to be reused.

WolfmanDragon
Package visibility is Java's `friend`, though.
Pavel Minaev
A: 

Failure by Sun to incorporate new APIs into the platform quickly. If you're new to Java, and want to do some logging, there are about 100 different ways to do it. Which should you use? Who knows. There's too many choices, and you have to find out which one fits your needs. There should just be one way to do it, or at least a recommended way to do it.

bpapa
A: 

Lack of SIMD operators.

BigInteger should be autoboxed as well as Integer. (Even if you don't like autoboxing, if it applies to one then it should also apply to the other.)

Overloading + for string concatenation was a bad idea. It should have been a separate operator.

The implementors of the collections framework seem to have a strange set of priorities.

Have you ever wished you had

List<Integer> Arrays.asList(new int[] {1, 2, 3}); ?

Me too, but it's not in there.

Have you ever wanted to do Arrays.sort(new float[] {1.0f, 2.0f, 3.0f})? Me neither, but that is in there.

And on the subject of omissions from the collections framework, why not

<K, V> Map<K, V> Collections.weakKeys(Map<WeakReference<K>, V> existingMap)

instead of a separate WeakHashMap class?

finnw
+3  A: 

Ugly looking default GUI, I think Java would gain a lot if they provided a nice default look-and-feel.

Viktor Sehr
Not so much of an issue now as it used to be, but the negative stereotype probably still sticks for many people.
Jonik
Even due it's quite easy to change to the native LookAndFeel, I still think it's a problem that you can't provide a good looking, platform independent LookAndFeel. (Cause Metal is ugly)
Viktor Sehr
+1  A: 

Not that important, but something I never thought about before today:

BlueRaja - Danny Pflughoeft
A: 

Ones that have already been mentioned:

  1. No unsigned types - the worst thing here is that Gosling basically justifies this by saying that developers are too stupid to know how unsigned arithmetic works, so it's better to just not have them available.
  2. Primitives are not interchangeable with their equivalent classes. That is, an int is not an Integer and so on. The real killer is that if you have two Integer's that wrap the same value and you compare them, the comparison will return false since the Integer objects aren't the same object.
  3. Related to that, there's no operator overloading at all. I know people bitch about operator overloading, but they make life so much easier. They'd let Integer behave like an int, for one thing.
  4. Multiple inheritance. I'm willing to let this one slide since there are a lot of implementation nightmares involved, but it still lets you do things so much more cleanly. Sure it's abuseable, but if we removed everything abuseable from a programming language we'd have nothing left.

The one that hasn't been mentioned yet is the lack of basic enums. Sure, they added something they /called/ an enum in 1.5, but it's not. It's a neat construct, and it has its uses, but it's not an enum and it doesn't cleanly replace just having a bunch of constant int values.

There are other things that bug me, especially the things that make Java so slow, but those five are the things that irk me most from a strictly code development viewpoint.

Kevin
+1  A: 

Java believes its own hype.

No way to take off the training wheels. Whenever I have to use Java I feel like I am on a kiddy trike.

It is overly difficult to reuse code. Other languages encourage decoupling shared functionality from a single object, but in java the only way is inheritance which is often blocked for other reasons. How do you add a method to String?

No first class functions. Not everything is always object oriented.

Tying the class name to the file name. This makes it hard to use the same file in multiple projects.

No pointers.

No preprocessor. Unless your projects are very simple or very isolated, having a preprocessor is invaluable.

No manual memory management. It is convenient to ignore memory management sometimes, but not to be forced to it.

No way to tell if an object implements a method. The information is there, but hidden because somebody might be allergic to details or something.

No way to call a method on an arbitrary object by name. Right now you basically have to make an interface for every single function, when that should just be implied.

No consistency in the core data structures. There are so many implementations of lists and maps and vectors and arrays and none are interchangeable.

Not cross platform. The one strength of java should be that once you port the virtual machine everything else just works, but that is not always the case in practice. I have one product for two platforms and very little code works on both. There is not a single file that I could use in both versions of the same program without some modification.

Java always feels so slow. You can argue that it is just as fast as this or that, but my perception is always that if it was not java it would be much faster.

drawnonward
A: 

Java mixes up value and object identity equality by using the same operator == for both. Hence you have to use == for int, but equals() for Integer, and so on. A good example of a language doing this right is Python (value equality: == and !=, identity comparison: is and is not) and VB (value equality: = and <>, identity comparison: Is and IsNot).

Pavel Minaev