Hi, Despite that the work of the guys from SUN with the Java core API is awesome, as they are humans, they are not infallible. I have read in several books some criticism about Some huge mistakes that (my guess) are still there for backward compatibility and legacy code. My question here is which ones do you know?

As examples:

  • Observable is a Class. Should be an interface in order to allow inheritance.
  • Cloneable: It shouldn't be a marker interface. (Should have the clone method instead of be in Object class).
+14  A: 
  • Observable has to be a class so that it can actually store the Observers and call them with updates. However, it's pretty trivial to write your own MyObservable - for instance I frequently use a RMIObservable that fires the update over an RMI link.

  • The Date and Calendar classes suck rocks.

Paul Tomblin
My fave quotes on these 2 are from the old Java FAQ: "[Date] a very bad joke - a sobering example of how even good programmers screw up" and then, re: GregorianCalendar, "Sun licensed this overengineered junk from Taligent - a sobering example of how _average_ programmers screw up"
Don't use Observer/Observable. Use java.beans events, or something similar.
Tom Hawtin - tackline
JSR 3something > Date > Calendar, IMO.
Thomas Owens
What little was good about Date has now been deprecated, so we're forced to use the far more painful Calendar. :(
Brian Knoblauch
Tell me about it. I had a project a few quarters ago to implement a calendar for a class. Well, it was a pain because we didn't want to use deprecated methods and Calendar sucked so hard. And we didn't find Joda Time fast enough.
Thomas Owens
What's the difference between Vector and ArrayList again? :\
Link to mentioned FAQ: - question 5.8
Thorbjørn Ravn Andersen
+5  A: 

Public instance fields in many AWT classes

Jacek Szymański
+17  A: 

Stack inherits from vector rather than simply holding one, giving stacks vector methods and allowing clients to trivially break the abstraction. A classic example of inheritance being used when composition should have been.

Aaron Maenpaa
+13  A: 

Stack extends Vector! insanity.

if I am using a stack object I expect users to be able to push and pop, and err, thats about it.

The java Stack also has all the vector functionality like get and set.

A Stack class that had a vector member variable, and only exposes the methods that a stack should have is how this should have been done, imho. This is a great example of where Composition is more appropriate than inheritance.

Josh Bloch's excellent Effective Java book is a great book to read, and he points out several flaws in the Java API very eloquently. He has obviously thought long and hard around the subject, seeing as he was one of the Java architects.

David Turner
+7  A: 
  • java.util.Calendar is a example of bad API design. Try to calculate the difference in days between two calendars and you will see that code is not readable/clear/succinct. APIs to handle dates in Java are bad. But things is getting better.
  • Some parts of Collections API. Per instance, "sort" must be a java.util.List method (they can't do it now because of compatibility); "Stack extends Vector" and lack of ways to handle collections in a easily (predicates, transformers, filters, etc)
  • Layout managers in Swing: powerful, but totally complicated.
  • java.util.Properties is a HashTable. Non sense!
+4  A: 

In addition to the Observable, Date and Calendar suckiness that others have mentioned:

  • Class equality depends on the identity of the classloader. The result is that serialization and everything that depends on it is inherently broken.
  • the java.util.URL class. Equality of two distinct instances can change depending on whether you are online or not. Also, the classloader mechanism uses this class for some unfathomable reason.
  • the XMLGregorianCalendar that isn't... in other words, despite its name, it is not actaully a GregorianCalendar.
  • Every object in Java is a mutex, and has wait(), notify() and notifyAll() methods. While the synchronized keyword is very useful, I think it should be limited to objects that implement some Lock interface or something like that - like how the for-each loop is only useable on Iteratble objects.
Christian Vest Hansen
+6  A: 

Bit of an open-ended question this one. Even in Object:

  • clone. Just remove it - no replacement. Absolute evil.
  • finalizer. Gah.
  • wait/notify/notifyAll. Wrongheaded approach to threading.
  • hashCode. Seems unfair to support hash but not ordered structures. Also it (together with ==) make small immutable value objects less efficient.
  • equals. Asymmetric. Should NPE on null argument.
Tom Hawtin - tackline
If you take a minute to learn the wait/notify/notifyAll functions you'll see that they're great for building higher-level concurrency blocks. Or you could just use everything in java.util.concurrent.
I wasn't particularly clear. My problem with them is that they are based around intrinsic locks. It's better to use specific lock objects rather than automatically expose the API for every instance of every class.
Tom Hawtin - tackline
Is there really that much of an issue with efficiency over equals/hashcode. I work on a high-volume trading system and have never found this to be an issue. Implementing Comparable gives you ordered structures.
I'm not aware of efficiency problems with equals/hashCode. Not unless you write a really bad hash algorithm that causes HashMap to be full of collisions. The default implementations of equals and hashCode are inlineable and intrinsified.
Tom Hawtin - tackline
+21  A: 
  • Properties extends Hashtable. Aargh.
  • Every object being available for locking instead of specific lock objects(.NET has the same problem)
  • Every object having equality/hashcode - again .NET has the same problem, but at least they have IEqualityComparer<T> as well as IComparer<T>. This is the way that all maps etc should go, as there are multiple concepts of equality depending on circumstance.
  • The date/time API (new version in Java 7, I hope)
  • The async model of NIO is harder to grok than the async .NET model
  • No universal disposal interface - partly due to checked exceptions - which makes an equivalent of the "using" statement harder to cope with
  • Poor text encoding support (too much use of names as strings)
  • No unsigned byte type
Jon Skeet
There are some lock objects you can use in java.util.concurrent. In fact you could build your own locks fairly easily, all the tools are there.
Yes - but the fact that they're present for every objects increases the likelihood of abuse.
Jon Skeet
Property extends Hashtable - whats wrong with that?
Andreas Petersson
+1 for the lock comment
@Andreas: (I've corrected it to Properties, btw) - Hashtable allows you to map arbitrary object keys to arbitrary object values. Properties are meant to be string to string. Inheritance fails here. Properties should *contain* a Hashtable rather than subclassing it.
Jon Skeet
+1 for Properties extending Hashtable. That always made me sick. I think it's a leftover of the first Java-version, but annoying anyways.
+1 for date/time. Oh god date/time.
Kevin Montrose
You can actually use arbitrary objects for both property names and values. Not when reading/writing to property files, but you *can* use it as a global object store. Scary.
What's wrong with the date/time API? (It's not that I think it's great, I just haven't used it enough to run into any eventual limitations)
Firstly, it's full of those deprecated methods from the early versions. Secondly, it makes it hard to do simple operations (create a specific date/time in a given time zone). The calendar arithmetic is insanely complicated to understand and use correctly. The fact that everything's mutable makes it very hard to reason about the code. It doesn't distinguish between the concepts of a time, a date/time, a local date/time etc. The time zone database is hard to update as it's part of the JRE. Joda Time is *much, much* nicer.
Jon Skeet
+7  A: 

Date being mutable

+13  A: 


+8  A: 

One big mistake was to create String(byte[] bytes) constructor and String.getBytes() method. They are the source of many problems with character encoding in java.

Those developers who know nothing about encodings use these methods without care. Code works on their environment and in their language. Bad luck if you have to reuse their libraries.

It is OK to use default encoding if you use it consciously. String(byte[] bytes, Charset charset) and String.getBytes(Charset charset) helps you be conscious.

Vilmantas Baranauskas
+4  A: 

From what I can tell, SimpleDateFormatter is convinced weeks start on Sunday and can't be dissuaded from this idea.

It's simple. :P
Chris Mazzola
Weeks do start on a Sunday in my part of the world!
John Topley
+3  A: 

Constructor of javax.naming.InitialContext requires Hashtable instead of a Map.

Vilmantas Baranauskas
Just to nitpick, is JNDI really "core" Java? Doesn't the "x" in javax mean extension?
Andrew Swan

In the String class:

public String(String string)

I don't know how many times I've seen code like

String cancel = new String("Cancel");

Sadly, this is the first example of a constructor introduced in Thinking in Java.

Unfortunately for you, this is vital. There are many cases where you absolutely have to do `String s1 = new String(s.substring(n, m))`
What you say is not true, you could write String s1 = firstString.substring(n, m); without any problem.
Juan Carlos Blanco Martínez
Regarding the String constructor: the newly created string is a copy of the argument string. Unless an explicit copy of original is needed, use of this constructor is unnecessary since Strings are immutable.
Juan Carlos Blanco Martínez
Can anyone give example of when "explicit copy of original is needed"?
Pavel Feldman
Yes... if your original string is very large, and you want small substring, then it's better to create a copy via new String(). This way, large array of chars in original string is not referenced anymore, and can be GC-ed (if original String is not needed)
Peter Štibraný
Now, everyone who hasn't read "Effective Java", please go and do so. Now!
+10  A: 

The java.sql API used to drive me crazy with its exception model. SQLException being a checked exception has led to enormous quantities of bad code around SQL calls: There's a million of DAO methods that either throw SQLException themselves, or just swallow or log exceptions. It should just be an unchecked exception: Unless you're building an SQL GUI tool, SQLExceptions usually mean that your code is broken or there's something wrong with the database server.

At the same time, SQLException doesn't give you much usable information on what went wrong - if you want to deal with errors in any meaningful way, you're forced to parse RDBMS-specific error messages.

This has been less of an issue since we have useable ORM frameworks. The Spring framework has also helped with it's higher-level JDBC support code and exception model.


You can fake unsigned integer types by going up one storage class (byte->short, short->int, int->long). But you can't get an unsigned long.

+5  A: 

Lots of uses of the Interface Constants anti-pattern, especially in Swing.

+5  A: 

Iterator is in java.util, while Iterable is in java.lang, although it depends on Iterator. Wrong package dependency :-(, thus these packages are effectively tied together.

Peter Štibraný
I'd say that's a rather minor problem (compared to others mentioned here), as both packages are in the core API and will always exist. Iterator would probably haven been moved to java.lang when Iterable was introduced if that where a compatible change (which it absolutely isn't).
Joachim Sauer
It's not big problem usually, but it is one of many small issues. Modularity matters, and bad examples in core library don't make it easier for people to learn good practices.
Peter Štibraný
+2  A: 

RuntimeException should not inherit from (Checked)Exception. It should be reversed (and named changed to reflect this), or RuntimeException and CheckedException should both extend Exception, and Exception and Throwable should have no public constructors.

Kevin Peterson
To be honest, I'd say that the real antipatter are checked exceptions themselves.
Michael Borgwardt
+2  A: 

My personal least favorite is that they have to retain the lovely public static final int literals for every pre-1.5 class. Why can't they enum clean the code base, por favor?

Downwards compatibility. It's extremely important to Sun, and rightfully so - IMO it's a major reason for Java's success in the business world.
Michael Borgwardt
+4  A: 

java.awt.BorderLayout uses NORTH, SOUTH, EAST, WEST instead of TOP, BOTTOM, LEFT, RIGHT. I also like the way they need to clarify it in the comments for those contants:

 * The north layout constraint (top of container).
public static final String NORTH  = "North";
Luke Quinane
+4  A: 

Here is a little list I have put together Java Convention Failure

One of my favourite is the rather long class name

A non-haiku I wrote in its honour ;)

Internal frame
internal frame,
title pane
internal frame.

title pane
maximize button,
window not focused state
Peter Lawrey
+1  A: 

Having public constructors instead of static factories that would return interfaces. Now they are stuck with concrete classes, and its harder to optimize things, or fix problems.


Its not an API issue, but a core anti pattern for me is not allowing unreachable code. I definately don't think unreachable code should be encouraged but a warning (C# style) would be fine. I don't know how many times I've had to do this:

if (true) throw new IllegalStateException("Testing... 123");  

// Unreachable code ....

Its worse still if you want to skip a block of code temorarily, i.e. you need to wrap it in if (false) { ... }

Luke Quinane
At least in Eclipse, the default behavior (I think) is to warn about unreachable code. Not allowing unreachable code at all seems like a really stupid idea, especially in the absence of a preprocessor.
What can you do with this that you cannot do with block comments? I see no purpose in allowing unreachable code.
Christian Vest Hansen
+2  A: 

java.awt.Graphics.drawImage(Image img, ...) only accepts BufferedImage at runtime.

If you subclass Image and try to draw it, you get an IllegalArgumentException: Invalid Image variant.

And admitting this in a comment is even worse, if you look up in the source code you will see:

 * In practice only a BufferedImage will get here.  

The List's toArray() methods:

T[] List<T>.toArray(T[] a)

I understand that they had to keep the original method for backwards compatibility but why did they only add Arrays.asList() without adding Arrays.<T>toArray(Collection<T> c)?

It makes working with JTree selection painful: tree.setSelectionPaths(selectionPaths.toArray(new TreePath[selectionPaths.size()]));

Luke Quinane