views:

415

answers:

8

I remember reading a book named:

Java Puzzlers Traps, Pitfalls, and Corner Cases

that described odd behavior in Java code. Stuff that look completely innocent but in actuality perform something completely different than the obvious. One example was:

(EDIT: This post is NOT a discussion on this particular example. This was the first example on the book I mentioned. I am asking for other oddities you might have encountered.)

Can this code be used to identify if a number is odd or not?

public static boolean isOdd(int i) {

    return i % 2 == 1;

}

And the answer is of course NO. If you plug a negative number into it you get the wrong answer when the number is odd. The correct answer was:

public static boolean isOdd(int i) {

    return i % 2 != 0;

}

Now my question is what are the weirdest, most counter intuitive piece of Java code you came across? (I know it's not really a question, maybe I should post this as a community wiki, please advice on that as well)

+2  A: 

In fact, Java Puzzlers has 94 more puzzles which exhibit sometimes strange and sometimes deceiving behaviors by mostly innocent-looking code.

coobird
+1, really hard to über the book.
kd304
hehe i don't know if you noticed but that's the source i mentioned in my question. The point is to find new oddities.
Savvas Dalkitsis
But not impossible, see my answer.
kd304
i lost you... can you elaborate?
Savvas Dalkitsis
@Savvas: I was just continuing my comment after my answer
kd304
+2  A: 

The most counterintuitive concept I came across is the PECS (Producer Extends, Consumer Super) from Josh Bloch. The concept is excellent, but what do you consider the consumer/producer in a situation - the method itself I would think at first. But no, the parameter collection is the P/C in this concept:

public <T> void consumeTs(Collection<? extends T> producer);
public <T> void produceTs(Collection<? super T> consumer);

Very confusing sometimes.

kd304
A: 

I tend to agree with you, but I have read (and hopefully someone can supply a link or two to) articles that explain that Java's '%' is consistent with its '/', and that is enough for anyone. From my own experience:

Java's '%' operator is a little different from some other languages' in its handling of negative inputs. I personally prefer "modulo" operators that return non-negatives, e.g.

-5 % 2 == 1

Which would make your example work. I think there is an official name for this operation, but I can't think of it now so I'll stick with "modulo". The difference between the two forms is that that Java variant of 'a % b' performs 'a/b' and rounds towards zero (and subtracts that result from 'a'), while the preferred operation rounds down instead.

Every practical use of applying % to negative 'a' and positive 'b' that I've seen works more easily if the result 'r' is '0 <= r < b' (one example is finding the offset from the left-most edge of a tile, when mapping points onto tiles on a plane that may extend '< 0'). The one exception to this experience was in a university assignment that performed static analysis of integer arithmetic in Java programs. It was during this assignment that the subtleties of Java's '%' came to light, and I went out of my way to replace it with the "fixed" version. This all backfired, because the point was to simulate how Java does arithmetic, not to implement my own preferred kind.

Edmund
nice answer but i must unfortunately say that it is a bit off topic. I was asking for general oddities not specifically this one. but thanks for the reply.
Savvas Dalkitsis
A: 

Odd and even numbers are usually thought of as positive numbers, so I think don't think its useful to think of negative numbers as odd or even. The test is often really to see if the lowest bit is set.

These are both fine for negative numbers as well.

if ((i & 1) == 0) // lowest bit not set.

if ((i & 1) == 1) // lowest bit set.

or

if ((i & 1) != 0) // lowest bit set.
Peter Lawrey
i was not asking specifically for this example. I know its problem. Please read the question. And FYI saying that negative numbers should not be considered odd or even is just WRONG (i am a math major trust me). Also I'm sorry if this comment came of a bit aggressive it is not my intention.
Savvas Dalkitsis
+3  A: 

One I blogged about recently, given the following two classes:

public class Base
{
   Base() {
       preProcess();
   }

   void preProcess() {}
}


public class Derived extends Base
{
   public String whenAmISet = "set when declared";

   @Override void preProcess()
   {
       whenAmISet = "set in preProcess()";
   }
}

what do you think the value of whenAmISet will be when a new Derived object is created?

Given the following simple main class:

public class Main
{
   public static void main(String[] args)
   {
       Derived d = new Derived();
       System.out.println( d.whenAmISet );
   }
}

most people said it looks like the output should be "set in preProcess()" because the Base constructor calls that method, but it isn't. The Derived class members are initialized after the call to the preProcess() method in the Base constructor, which overwrites the value set in preProcess().

The Creation of New Class Instances section of the JLS gives a very detailed explanation of the sequence of events that takes place when objects are created.

Bill the Lizard
very very nice. this not only is counterintuitive but also looks like it should work this way.
Savvas Dalkitsis
Note also that Josh Bloch, in one of his books, discourages calls to overridable methods in constructors (and I believe synchronized methods).
Jack Leow
(Discourages the use of overridable methods in synchronized methods is what I meant to say, not discourage the use of synchronized methods in constructors - though I may be incorrect about this point, I should probably double check it)
Jack Leow
+2  A: 

We once stumbled upon something like this in a legacy code base (originally camouflaged by a 5 level inheritance structure and several indirections):

public abstract class A {
    public A() {
        create();
    }
    protected abstract void create();
} 

public class B extends A {
    private Object bMember=null;
    protected void create() {
        bMember=getNewObject();
    }
}

When you call B constructor, it calls A default constructor, calling B's create() method, through which bMember gets initialized.

Or so we naively thought. Because after calling super(), the next step in the initialization process is the assignment of explicitly defined default values to B members, in effect resetting bMember to null.

Program was actually working fine anyway, because bMember got assigned again through another route later on.

At some point we removed the apparently useless null default value for bMember, and suddenly program behavior changed.

Nicolas Simonet
ah, just noticed Bill the Lizard posted a better version of this problem earlier... oh well
Nicolas Simonet
nice. same as http://stackoverflow.com/questions/1147245/java-counter-intuitive-code/1147385#1147385 but still a very counter intuitive piece of code.
Savvas Dalkitsis
:D you were faster than me.
Savvas Dalkitsis
"originally camouflaged by a 5 level inheritance structure and several indirections" That makes this a pretty nasty inconsistency to track down, and is almost exactly how a co-worker of mine discovered it. :)
Bill the Lizard
+1  A: 

i recently discovered that Math.abs(i) does not always produce positive numbers.

Math.abs(Integer.MIN_VALUE) yields -2^31

why? because there is one less positive Integer than negative. 2^31 is one more than Integer.MAX_VALUE and thus overflows to -2^31

i guess the situation is similar in most other languages, but i encountered this in java

Andreas Petersson
Good one. It turns out this is also part of the API documentation:"Returns the absolute value of an int value. If the argument is not negative, the argument is returned. If the argument is negative, the negation of the argument is returned. Note that if the argument is equal to the value of Integer.MIN_VALUE, the most negative representable int value, the result is that same value, which is negative."
Savvas Dalkitsis
A: 

Have a look at the methods defined in java.util.concurrent.SynchronousQueue: http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/SynchronousQueue.html

Half of the methods always return null / true / false / zero:
Not exactly obvious when you first start working with it, without reading the docs first.

Tim