views:

846

answers:

17

I was recently trying to convert a string literal into a boolean, when the method "boolean Boolean.getBoolean(String name)" popped out of the auto-complete window. There was also another method ("boolean Boolean.parseBoolean(String s)") appearing right after, which lead me to search to find out what were the differences between these two, as they both seemed to do the same.

It turns out that what Boolean.getBoolean(String name) really does is to check if there exists a System property (!) of the given name and if its value is true. I think this is very misleading, as I'm definitely not expecting that a method of Boolean is actually making a call to System.getProperty, and just by looking at the method signature, it sure looks (at least to me) like it should be used to parse a String as a boolean. Sure, the javadoc states it clearly, but I still think the method has a misleading name and is not in the right place. Other primitive type wrappers, such as Integer also have a similar method.

Also, it doesn't seem to be a very useful method to belong in the base API, as I think it's not very common to have something like -Darg=true. Maybe it's a good question for a Java position interview: "What is the output of Boolean.getBoolean("true")?". I believe a more appropriate place for those methods would be in the System class, e.g., getPropertyAsBoolean; but again, I still think it's unnecessary to have these methods in the base API. It'd make sense to have these in something like the Properties class, where it's very common to do this kind of type conversions.

What do you think of all this ? Also, if there's another "awkward" method that you're aware of, please post it.

N.B. I know I can use Boolean.valueOf or Boolean.parseBoolean to convert a string literal into a boolean, but I'm just looking to discuss the API design.

+2  A: 

I agree. I've always been uncomfortable with those methods.

I've even found a bug in our code base that was caused by someone using Integer.getInteger() to parse a string, not realizing that it was looking up the property.

Unfortunately, of course, there is no way that the API can ever be removed, for backwards-compatibility reasons.

Avi
they should deprecate it ASAP.
Andreas Petersson
+10  A: 
String.getBytes()

often the cause of lots of stupid character encoding problems in applications because it uses the underlying platform character encoding.

Jon
Even more so: FileReader, which doesn't even *have* a constructor that allows you to specify an encoding.
Michael Borgwardt
From javadoc: The constructors of this class assume that the default character encoding and the default byte-buffer size are appropriate. To specify these values yourself, construct an InputStreamReader on a FileInputStream.
gnud
@gnud: But the point of `FileReader` is to act as a convenience class that allows you to read files without having to use those classes. Indeed, `FileReader` **is an** `InputStreamReader` which uses a `FileInputStream` if you look at the source, hence, it should definitely allow one to set the `Charset` through the ctor, just like its parent class.
JG
There are a hundred places where Java allows or encourages you to omit the charset. This is unfortunate, as it almost always causes an obscure little bug your US-based testers won't notice. The platform ‘default encoding’ is worse than useless. Is there a Java lint anywhere that will flag this usage?
bobince
So whats the correct way of getting the `String.getBytes()`?
Shervin
Pass it the charset instead as a String: String.getBytes("UTF8") or by using a Charset object.
Jon
+6  A: 

InputStream.read(byte[])

Doesn't fill the array; instead it reads an arbitrary number of bytes and returns that number. You have to loop. Nasty, because it works correctly for small arrays most of the time. I don't think anyone gets this right the first time they use it.

Michael Borgwardt
@Micheal: but it has to work that way! Imagine the howls from the J2ME crowd if the (only) block read method allocated its own byte array.
Stephen C
It wouldn't have to; Ideally the looping would be implemented in the method. Since it blocks anyway, there is no conceivable advantage to the way it works now.
Michael Borgwardt
It works exactly the way a C programmer would expect it to ;P
KitsuneYMG
Ditto (what @kts said)
Jason S
Yep. I'm with @kts too. I got it right the first time because I got it wrong the first time I used it in C :)
Dave Ray
@Michael: what about the last read? How can read return a full buffer if you reached EOF when the buffer is half full???
Stephen C
Yes, you'd still have to return the number of bytes read, but the caller wouldn't have to do the loop, and in many cases (mainly when reading files) you can preallocate the buffer to the correct size.
Michael Borgwardt
+3  A: 

I'm not sure if anyone still uses this but the error message from DocumentBuilder.parse() if something goes wrong is (almost?) always "Content is not allowed in prolog." even if the real reason was something else entirely.

Buhb
Yes I faced this many times....
techzen
+20  A: 

The URL equals() method compares IP addresses, uses a network connection and is a blocking operation!

From the javadocs:

Two hosts are considered equivalent if both host names can be resolved into the same IP addresses; else if either host name can't be resolved, the host names must be equal without regard to case; or both host names equal to null.

Since hosts comparison requires name resolution, this operation is a blocking operation.

Note: The defined behavior for equals is known to be inconsistent with virtual hosting in HTTP.

Use URI instead.

dogbane
+18  A: 

One well-known problem with the Calendar class is that months are numbered 0 to 11 instead of 1 to 12. It's very easy to make a mistake like this:

Calendar cal = Calendar.getInstance();

// Set date to August 18, 2009? WRONG! Sets the date to September 18, 2009!
cal.set(2009, 8, 18);

The right way to do it is by using constants for the months:

cal.set(2009, Calendar.AUGUST, 18);

But the method makes it much too easy to make the mistake of using the normal month numbers 1 to 12.

I regard this as a mistake in the design of the Calendar class.

Jesper
It was designed that way so that you could look up, in a standard 0-based array, what the name of a month was given its number. Besides, everybody uses the constants, don't they? :-P
Jonathan
this was designed before enums
Jason S
If the Calendar class provide the lookup facility (With I18N support, of course) then the zero based farce would never have been necessary in the first place. Anyway, most programmers are used to removing or adding one, in order to deal with indexes but - at the end of the day - a month is an ordinal value, starting at one, and this convention has been around for so long it was a very bad decision to ignore the convention for such a pathetic reason. This is made even more annoying by the fact that the DAY_OF_WEEK values go from 1 to 7!!!
belugabob
I think this is yet another hand-me-down from a well-known C API - including the inconsistency between months and days.
Michael Borgwardt
+4  A: 

my issue is with String's substring method; every time I use it I have to write out the word "hamburger" and "hamburger".substring(4,8) = "urge" to remember how to use it correctly

Jill Renee
Most substring/slicing/subset APIs work in a similar manner, so I'm not sure how confusing this really it. I've come to expect that such ranges are clopen—closed on the bottom but open on the top. It makes iteration that much easier, too.
jasonmp85
The main reason this is done with ranges is that the width of the (integer) range [4,8] is 5; the range starting at 4 with width 4 is [4,7]. Using floating-point numbers, this is no longer true! This is because the integer range [4,8] should really be written [4,9) (which also makes calculating the widths much easier...)
BlueRaja - Danny Pflughoeft
+3  A: 

It's probably not the worst method, but I never liked this one:

Suppose x is a list known to contain only strings. The following code can be used to dump the list into a newly allocated array of String:

String[] y = x.toArray(new String[0]);

Passing an String array of the size 0 to the method just seems crazy and unintuitive to me.

Otto Allmendinger
Yes, it's a total bummer, but it's the only way to infer the type, due to type erasure.
JG
Actually you get slightly better performance if you write x.toArray(new String[x.size()]). Then it fills the array you allocated and passed in, rather than looking at the type of the passed-in array, throwing it away, and creating a new array. But I agree, it's very awkward. I would have thought that when they added templates they would have created a cleaner alternatively, but apparently not.
Jay
+4  A: 

Just found out about the methods isInterrupted and interrupted of class Thread. From javadoc:

static boolean interrupted()
// Tests whether the current thread has been interrupted.
boolean isInterrupted()
// Tests whether this thread has been interrupted.

The problem is that interrupted actually clears the interrupted status besides doing the test, while isInterrupted just tests the status.

JG
This is indeed very confusing. Be careful when using static interrupted() method. On the other hand, it's handy when doing `if (Thread.interrupted()) throw new InterruptedException();` (You usually want to clear interrupted status when throwing this exception).
Peter Štibraný
+2  A: 

BigDecimal.setScale(int) a setter that returns a BigDecimal hmmm

keuleJ
This is a common pattern...and there's a proposal to make all setters act this way. It allows method chaining.Person person = new Person().setFirstName("James").setLastName("Gosling");
Steve McLeod
BigDecimal is *immutable*, so it can't set scale on existing object, but has to return new one.
Peter Štibraný
@Peter: I know that, but I think the name of the method is a bit misleading. In my intuition a setter changes something on an object. So maybe I would call the method BigDecimal.convertToScale(int) or something like that. But hey, it's clearly documented, so it's not that big of a problem.
keuleJ
I see. I agree that it is little misleading.
Peter Štibraný
+3  A: 

Some redditor noticed that String.substring leads to memory leaks, because internally it does not copy substring, but just copies pointer to whole string + offset + length. So if you expected whole string to be collected by GC, you are screwed.

http://www.reddit.com/r/programming/comments/8ydvg/the%5Fdangers%5Fof%5Fstringsubstring/c0au0gj

maykeye
Well, because strings are immutable this makes sense as it allows for sharing. Of-course there is the subject of having a small substring from a large string in which case the string is not GCed.
Shimi Bandiel
Ohhh yes... I've run into that... getting a list of words from a few hundred 100k-2mb files. Took far too long to figure out that OutOfMemoryException.
CoderTao
A: 

I wouldn't file it under "Most Awkward", but java.security.MessageDigest.getInstance() gave me some confusion.

I'm typically used to see a "getInstance()" method return a Singleton.

If a method is to return a New Instance, i might expect to see a MessageDigestFactory.newInstance(), or at the very least a newInstance() on the MessageDigest class instead of their getInstance() method.

See: MessageDigest.getInstance()

From what I've tested, MessageDigest.getInstance() returns a New Instance, every single time it's invoked.

Chris Holland
Well, what about Calendar.getInstance()? It doesn't return a singleton either.
Shimi Bandiel
ah yea, good point. I guess this pattern's used more pervasively than i thought :/ It just 'feels' odd.
Chris Holland
+3  A: 

Well, System.setOut() will set the value to a final member of System!!!!

Shimi Bandiel
IMO, the real issue is that System.{in,out,err} should be static methods not static final members.
Stephen C
+2  A: 

I never really understood why the JDBC API consistently starts counting with 1, while the rest of the Java ( and C, C++, C#, ...) universe starts at 0. This applies for column numbers, parameter numbers in prepared statements etc.

mkoeller
In itself, I think the designer of the JDBC API made the right decision starting numbering at 1. But in light of the rest of the Java universe, it is damn confusing.
Steve McLeod
i just started working with jdbc and noticed this. At least its clearly defined in the javadocs...
luke
+2  A: 

One of my pet peeves with Java is the fact that a failure in Integer.parseInt("SomeString") merely states that there was a parse error, failing to tell us what the "SomeString" was. Because of this, it is sometimes necessary to do loads of debugging to find out what the string was. If the error mesage included the erroneous string, tracking down the problem would be much quicker.

belugabob
Integer.parseInt("SomeString"); gave me `Exception in thread "main" java.lang.NumberFormatException: For input string: "SomeString"`
Peter Štibraný
But maybe it's specific to your class library (I used Sun Java).
Peter Štibraný
Are you using Java 6? - I haven't used Java for a while, so my experiences may relate to an earlier version.
belugabob
+8  A: 

Just got this one from here, regarding the add and remove methods of List (when parameterized with Integer). For instance:

List<Integer> l = new ArrayList<Integer>();
l.add(20);
l.remove(20); // throws ArrayIndexOutOfBoundsException, because it will try to access index 20
l.remove(new Integer(20)); // this works
JG
Good example why you should never use magic numbers
Lumpy
@Lumpy You would have the same effect with int variable.
Nikita Rybak
I would never see a case where you would have a list of Integer then try and remove an int.
Lumpy
A: 

java.util.Date.getDate() returned a number, 1-31. getDayOfMonth() is the accurate way to explain it, whereas you were usually trying to remember getTime().

Cannot wait for Joda Time to take over.

Dean J