What is your "favorite" API annoyance or missing feature or misengineered part?
java.util.Date
[1] is one and all epic fail. The Calendar
isn't much better. I am really looking toward
JSR-310
[2]. Until then
Joda Time
[3] is a perfect alternative.
Edit: Oh, one more comes to mind: java.sql.Connection
, Statement
and ResultSet
doesn't implement kind of Closeable
interface such as Java IO (finally)
has
[4] since 1.5. You have to write at least three almost the same utility methods to close all of them in a short and proper manner.
DATE
, TIME
or TIMESTAMP
in the DB in flavor of a Java object using the respective PreparedStatement
methods. - BalusC
Poor choices for of names are a favourite pet hate.
Classes which extend a class of the same name.
java.sql.Date [1] extends java.util.Date [2]
com.sun.corba.se.spi.orb.ORB extends com.sun.corba.se.org.omg.CORBA.ORB extends org.omg.CORBA_2_3.ORB extends org.omg.CORBA.ORB
Error which is not an error
com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError extends Exception
Exception which is not an exception
javax.print.FlavorException which is an interface
Confusing mix of case
com.sun.org.apache.bcel.internal.Constants.ArrayType which implement equals and hashcode but NOT hashCode()
Stupidly long class name
com.sun.java.swing.plaf.nimbus. InternalFrameInternalFrameTitlePaneInternalFrameTitlePaneMaximizeButtonWindowNotFocusedState
The last one I liked so much I wrote a poem
InternalFrame InternalFrame
Title Pane,
Internal Frame
Title Pane.
Maximize Button Window,
Not Focused State.
[1] http://java.sun.com/javase/6/docs/api/java/sql/Date.htmlMy favourite is java.net.URL
. .equals()
and .hashCode()
require network access, because of the silly spec that two URLs are equal if their domain names resolve to the same IP. Not only does this mean that putting them into collections is slow and doesn't work when the network has been firewalled out on a customer's site, but it means that two URLs that will serve different content with HTTP/1.1 will return equal.
SimpleDateFormat [1] is not thread-safe. I mean, how hard can that be to fix ?
[1] http://java.sun.com/j2se/1.4.2/docs/api/java/text/SimpleDateFormat.htmlThere's a String.split() method, but no String.join(). So annoying.
See also "Ten Little Soul Crushing Features of Java" [1]
[1] http://blog.darevay.com/2009/04/ten-little-soul-crushing-features-of-java/java.util.Stack
deserves a special mention for violating Object Oriented Programming 1-0-1:
Stack
inherits from Vector
but does not obey the "is-a" relationship typical of inheritance relationships. This (mis)implementation makes it possible to perform "illegal" operations on the stack such as inserting an element at an arbitrary position.
java.sql.Date
interits from java.util.Date
, but doesn't obey the "is-a" relationship. This is "clearly" documented, but leads to hibernate giving you "Date"s that are not comparable with your own "Date"s. - davidsheldon
The Boolean
class which defaults to false
.
When a boolean is created with Boolean( String )
or Boolean.valueOf( String )
any value other that "true"
(ignoring case) will lead to a boolean that is false
.
As a consequence, I've seen many property files or configuration with "0"
, or "No"
working correctly, but when toggled to "1"
or "Yes"
there is no effect.
I wish they had been more strict, and that any value other than "true"
and "false"
would yield a BooleanFormatException
in a way similar to Integer.valueOf( String )
.
For other usage we could use parseBoolean( String )
or a BooleanFormatter
...
One of my biggest Java API gripe is that String
's :
.getBytes("UTF-8")
is forcing you to catch a checked exception (UnsupportedEncodingException) which CANNOT happen. ("CANNOT" used as defined by RFC2119)
It cannot happen because if UTF-8 isn't supported by the VM then it's not a compliant JVM for every single JVM under the sun MUST ("MUST" used as defined by RFC2119) support UTF-8 or it is, well, not a JVM.
I've posted about this 10 years ago or so and people have looked at me as if I just landed from a long trip to Mars... Yet of course ten years later a company gave me justice: Google. There's at least one Google Java collection where they acknowledged this as a serious Java API issue and provided a convenience workaround.
Why oh why Java didn't have from the get-go a:
.getUTF8Bytes()
is beyond me.
In a totally ironic turn of event, the fact that they didn't provide such a method made countless typos in "UTF-8" trigger the UnsupportedEncodingException.
Promise I won't start ranting about checked exceptions (I've got my copy of "Effective Java" next to me and I'll read Joshua Bloch ranting about them for me ;)
String.getUTF8Bytes()
but rather the absence of a few static Charset
objects for all encodings Java is guaranteed to support, allowing you to say str.getBytes(Charset.UTF_8)
- getBytes(Charset)
doesn't throw anything checked. It simply makes no sense that you have to look up UTF-8, US-ASCII and other charsets which are guaranteed to be there, and it's not like it's hard to add a few public static final Charset
fields in an appropriate place. - gustafc
getBytes(Charset)
(available from 1.6) isn't declared to throw anything. So if you have a valid Charset
you won't have to do any try/catching. - gustafc
int, double, and other primitives cannot be used as generics
Not so much an annoyance as just plain wrong: there is a case where the following code can enter the final else {...}
part.
if (a==b) { ... }
else if (a<b) {...}
else if (a>b) {...}
else {...}
The case is:
Integer a = new Integer(1); Integer b = new Integer(1);
In case you wonder why: Some comparisons are unboxed, others are not.
==
. Much better to either just test for identity equality (==
) or object equality (object.equals(other)
). Better yet: if Java had operator overloading, it could do like Python: is
for identity equality and ==
for object equality; if ==
isn't implemented, it falls back to object identity (in which case, the object identity is object equality). I suppose your proposition would work if the compiler throws an error when an object doesn't implement ==
. - Longpoke
BalusC beat me to the date API, so I'll list my second one: The fact that clone()
is totally broken. I don't think there is anything about the API you could define as not broken, including naming.
try{ SomeStream = ... }
<- close implied (even if return or throw is involved). - java.is.for.desktop
The Cloneable [1] interface does not define the clone method (it's just a marker interface). So even if you know that an object implements Cloneable, you don't know whether it can actually be cloned (it might not have a public clone method).
[1] http://java.sun.com/javase/6/docs/api/java/lang/Cloneable.htmlClosing streams is a night mare.
close() throwing an exception ruins your code and does not help you at all. If you rethrow the exception of close() you loose the original exception and the original exception is usually the important one.
InputStream in = null;
try {
in = new FileInputStream(filename);
// ... some IO operations
} finally {
// This is the ugly part
try {
if (in != null)
in.close();
} catch (IOException e) {
//Ignore this exception (maybe log it)
//but never rethrow it.
}
}
The Exception hierarchy has always been broken in my eyes:
I've always thought it would make more sense for all java.lang.Exception and subtypes to be checked exceptions.
Having java.lang.RuntimeExeption inherit from java.lang.Exception but being unchecked is just broken.
throws Exception
to every method signature you create. - T.J. Crowder
Throwable
superclass. - finnw
A little pet annoyance is that
String#format
[1] is static and not an instance method.
I'd like to write:
"My %s format".format("Nice");
instead of
String.format("My %s format", "Nice");
[1] http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/lang/String.html#format%28java.lang.String,%20java.lang.Object...%29Oh gosh... I read the JavaDocs of the entire JDK for my Ph.D. and found so many annoyances beyond what already annoyed me from day-to-day programming.
To name a few from my own experience though:
Hashtable
vs. HashMap
and the threading issues).That being said, Hindsight is 20/20. It's hard to come up with the perfect API the first time around, and even harder to rectify it while maintaining backward compatibility.
This one is hilarious. You need to go past to check whether the last column read was null
or not.
This is the case when you get 0
from any of these ResultSet
's getInt()
, getDouble()
etc. methods. Then you have to check it whether it was really 0
or null
, by invoking wasNull()
on the ResultSet.
ResultSet#getObject()
is better: stackoverflow.com/questions/2158187/… - BalusC
I hate the fact that Java does not allow extracting static class metadata at compile (=coding) time. For example, there is no way to statically to refer to a function's name or a field's name for later reflection-use (for example). You must use a dummy constant (final static String FIELD_NAME = "fieldName") instead which is dumb as it could be more easily solved via native meta data reference (think enum and think enum's getName etc. or similar).
However, http://projectlombok.org/ can spice up java just like that.
But why is this not yet native java fuctionality? It should have been for so long now ...
Mine is that java.util.Map.get
does not accept a default object if they key is missing in the Map.
Therefore I find myself too much writing this code:
Object value = map.get(key) == null ? default : map.get(key);
UPDATE
After Pascal's comment showed me how all my code is buggy, should have been:
Object value = map.containsKey(key) ? map.get(key) : default;
key
is actually null
? - Pascal Thivent
Object value = map.get(key) ?? default;
(called the null-coalescing operator), or wait until future Java releases (as far as I know, it won't be in Java7). - BalusC
if (!map.TryGetValue(key, out value)) value = defaultValue;
- 280Z28
GetOrAdd
method, but that's not the case since you're getting the key twice. TryGetValue
is perfect for the use here, and the new ConcurrentDictionary
type in .NET 4 does have a GetOrAdd
method, which takes either a value or a function to lazy-eval: msdn.microsoft.com/en-us/library/ee378676(VS.100).aspx - 280Z28
The XML APIs: SAX, DOM, StAX.
I agree that stuffs have improved with StAX, but it is still waaaay to complicated. We can of course blame XML for being an "only apparently" simple technology. Dealing with namespaces, entity, CDATA, etc. can make a trivial problem become a nightmare.
But I still haven't digested the ugliness or reading XML with SAX and DefaultHandler#character()
being sometimes called more than once per tag. Even if there is a rationale for that, it's still bad API to me.
+1 for Date/Calendar API
Also the implementation of generics is pretty bad. Type erasure leads to some weird situations that are difficult to deal with. Also wildcards are confusing from time to time even after using them for years. One more gripe is that the generics syntax is overly verbose:
Map<Integer, String> someMap = new HashMap<Integer,String>();
This will be fixed in Java 7 with generic type inference so the above line will end up looking like this:
Map<Integer, String> someMap = new HashMap<>();
ByteBuffer as a Class with no corresponding Interface in NIO.
There is no way to create a "custom" ByteBuffer implementation. (ByteBuffer can not be extended due to access levels of the constructors.)
I hate how JDBC PreparedStatement
derives from Statement
, and then proceeds to override half of the latter methods (essentially all that make it a "statement") with throwing stubs, replacing them with its own equivalents.
Ultimately, it exposes the design flaw of Statement
class, instances of which - contrary to its name - do not represent statements at all. Instead, they are kinda result cursors in disguise (due to "one open ResultSet
per Statement
" rule), though what's the purpose of having such an object is completely beyond me.
String comparison:
if ("somestring".equals(foo)) ...
instead of
if (foo == "somestring") ...
"You can't be serious!" -- John McEnroe
My recently found annoyance with Java.
BufferedImages [1] have the functions getRGB and setRGB which are nice, however they return an int and not Color. So if you would like to get the individual components without direct manipulation you would have to create a color object just for that, and then convert it back to int just to set the RGB.
[1] http://java.sun.com/j2se/1.4.2/docs/api/java/awt/image/BufferedImage.htmlA decent class for simple monetary calculations. BigDecimal is a right PITA to use if all you want is to do some invoicing for instance.
There isn't even a method to quickly multiply by an integer or calculate a percentage. Would be great to have a class Monetary capable of these things.
I'm thinking along the line $12.98 * 5 * 12.5%
Monetary m = new Monetary("12.98");
Monetary tax = m.multiply(5).percentage(12.5)
I have two favorits regarding java collections (beside some allready mentioned here):
1) java.util.Map<K,V>.get
: takes Object as argument not K as parameter type. I don't know if there is any good reason for this, I think its just anoying. If you change the type arguemnts of the Map instance you do not get any feedback from the compiler that your call to Map.get is faulty.
2) Searching java colelctions: java.util.Collection<T>
just defines contains
with a single argument of type (again) Object (why object and not T?) so I have no possibility to search the collection for other predicates than equals. Ironically there exists an interface called Compareable
, which seems only to be used by binarySearch
, not by contains
, and sorting all your collections all the time is not very useful IMHO.
.equals
(which is what almost all maps use to do the lookup) is defined on Object
, not on K
. Would it have been possible to make it so that you could only call equals
on two objects of the same type? I'm not sure, especially because it's not clear what "same type" would mean in this case. - MatrixFrog
Map
is actualle my favorite example, but there is more. Cloneable
(besides other issues) should be Cloneable<T extends Cloneable>
- Raphael
Integer, Double,... comparison.
if (oneDouble.compareTo(otherDouble) > 0)
or
if (oneDouble.isGreaterThan(otherDouble))
and of course all the analog.
(Input|Output)Stream.close() throws a checked exception which means you have to litter your stream handling code with nested try/catch blocks.
The proliferation of CHECKED exceptions throughout the API. Most notably, java.sql.SQLException and java.io.IOException. They should be unchecked exceptions.
Adding throw statements up your call stack until you get to the method that can handle them is ugly and tedious. And the nested Try-Catch-Finally's to close jdbc connections are a joke.
Unchecked
interface instead, then some specific exceptions that are clearly programming errors (e.g. SQL column index out of range, trying to write to a closed stream) could be uncheckd while exceptions that were outside the programmer's control (e.g. file not found, unexpected SQL schema change) would remain checked, and this would be orthogonal to whether the exception came from java.sql
or some other subsystem. - finnw
PreparedStatement
and retrying the transaction (which well-written programs are capable of doing anyway.) And it's not super-rare for web apps. Some apps (like StackOverflow) just go offline for a couple of hours if they need to change the schema, but some apps really must not go offline and must handle schema changes (facebook, google web search etc.) Others (Twitter) shouldn't go offline but do. - finnw
The collection api is mutable - thats ugly. But why there are to similar types Enumeration
and Iterator
? They just can have made Iterator extends Enumeration
and introduce Enumerable
instead of Iterable
in Java 5. Now you always have to deal with both, adapt one to the other, i hate it.
(copied from question 169815 [1])
This one still catches me out occasionally:
When you create a
duplicate
[2]
or
slice
[3]
of a
ByteBuffer
[4]
, it
does not inherit the value of the
order
property
[5] from the parent buffer, so code like this will not do what you expect:
ByteBuffer buffer1 = ByteBuffer.allocate(8);
buffer1.order(ByteOrder.LITTLE_ENDIAN);
buffer1.putInt(2, 1234);
ByteBuffer buffer2 = buffer1.duplicate();
System.out.println(buffer2.getInt(2));
// Output is "-771489792", not "1234" as expected
[1] http://stackoverflow.com/questions/169815/java-common-gotchasThe java.math.BigInteger class is a total joke without operator overloading. Something as simple as (a+b)-c becomes (a.add(b)).subtract(c).
Lack of a MultiSet container.
+ the points raised in other posts (especially Date).
Aside from SimpleDateFormat not being thread safe, the equals and hash code methods of java.lang.URL [1] doing external lookups, which is particularly annoying if the addresses point to two different virtual hosts with the same IP address.
[1] http://java.sun.com/javase/6/docs/api/java/net/URL.html#equals%28java.lang.Object%29Collection
interface has contains
method which returns boolean but no find
method. Set
doesn't have find
either, so it ends up with
Map<Type, Type> myMap = new HashMap<Type, Type>();
myMap.put(obj, obj);
or similar.
contains
method sufficient? You need a reference to the target object to call contains
anyway so returning a boolean is sufficient. If you want to search the data structure then you need to iterate over its elements. - maerics
equals
? Do you iterate over HashSet to find specified element? - Tadeusz Kopec
The inconsistent iterator pattern.
In Java you have the Iterator
and Enumeration
interfaces for iterating over sequences. Moreover, the JDBC class ResultSet
has its own iteration pattern via the next
method. There should be a single, language-supported way to iterate ordered sequences.
The introduction of the for-each loop in Java 1.5 helps for arrays and Iterators, but enumerations and result sets still have their own styles, so if you want to iterate over a sequence you must know what type of sequence it is.
PathIterator
- finnw
that a method having an argument of type
MyClass<AnyType>
leads to the same signature as
MyClass<AnotherType>
does...
Missing of operator overloading.
I think java persistent API