tags:

views:

516

answers:

5

I have a really strange enum bug in Java.

for(Answer ans : assessmentResult.getAnswersAsList()) { //originally stored in a table
    //AnswerStatus stat = ans.getStatus();
    if (ans.getStatus() == AnswerStatus.NOT_ASSESSED) {
        assessed = false;
    }
}

An answer is an answer to a question on a test. An assessment result is the result a student gets on a test (this includes a collection of answers).

I've debugged the above code, and ans.getStatus() returns AnswerStatus.ASSESSED. Still, the if line returns true, and assessed is set to false.

But, the thing I think is most strange; When I declare the AnswerStatus stat variable, it works, even if I don't use the stat variable in the if test. Could someone tell me what is going on?.

I've read something about enum bugs in serialization/RMI-IIOP but I don't use that here. The enum AnswerStatus can be ASSESSED or NOT_ASSESSED.

The getStatus method in class Answer just returns the status, nothing else.

+1  A: 

What happens if you use .equals instead of ==?

Phill Sacre
That shouldn't change anything. Enums are defined to have unique identity exactly so that you can use "==" to test for equality.
Joachim Sauer
taken from Enum.java :public final boolean equals(Object other) { return this==other; }so it won't change anything!
romaintaz
It can be different. For example, if one of the enum objects is received via IIOP it will be different from the constant object on the local machine. This situation can be avoided by implementing a readResolve method.
Dan Dyer
Dan: are you sure that's still true for Java 5 enums? As far as I know that was only a problem when implementing your own enums in pre-Java 5.
Joachim Sauer
It happened to me with Java 5. See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6277781
Dan Dyer
A: 

Same thing. I've read that java.lang.Enum makes equals final, and implements it to return this == other.

Please don't add information as an answer, but post a comment or edit your question, answers are meant only for ... well, answers.
Joachim Sauer
ok, sorry. First time @ StackOverflow :)
+2  A: 

I've debugged the above code, and ans.getStatus() returns AnswerStatus.ASSESSED. Still, the if line returns true, and assessed is set to false.

But, the thing I think is most strange; When I declare the AnswerStatus stat variable, it works, even if I don't use the stat variable in the if test. Could someone tell me what is going on?.

This sounds like the getStatus() method does not always return the same result - how is it implemented?

BTW, what's the point in having an enum with the values ASSESSED, and NOT_ASSESSED? Why not use a boolean isAssessed()?

Michael Borgwardt
I believe it is considered clearer and more extensible to use an enum for something like this.
ColinD
@Colin: Not if it doesn't work ;) If there are only two possible states and one state is the logical negation of the other, a boolean is simpler.
Dan Dyer
The reason is that it is not clear yet if these are the only statuses for the answer.
boolean is clearer for something is 2-state. By using an enum it's essentially 3-state; ASSESSED, NOT_ASSESSED and null.
Steve Kuo
+2  A: 

Solved.

It was the NetBeans debugger that tricked me. It does not pass the if test (although NetBeans says that).

Sorry for the inconvenience :-)

A: 

No answer to your question but a suggestion:

It's always better to place the fix enum value in the first place in the compare statement and the variable part in the second place. Because, if in any circumstance the variable part delivers NULL you won't get a NullPointerException.

In your example it will look like this

...
if (AnswerStatus.NOT_ASSESSED == ans.getStatus())
...

MISTAKE:

Of course I make a mistake and mixed two things with each other. If you use the equals method to compare a fixed enum value with a variable containing this enum it's good to compare the constant enum value with the variable and not vic versa. For example:

write

if (AnswerStatus.NOT_ASSESSED.equals(ans.getStatus()))

instead of

if (ans.getStatus().equals(AnswerStatus.NOT_ASSESSED))

because, this could harm a NullPointerException if ans.getStatus() == null.

Goran Martinic
null==something will not result in a null pointer exception.
Steve Kuo
You are right. Thanks.
Goran Martinic
You're thinking of something like "Some constant".equals(someVariable) or someConstant.equals(someVariable)
Scott Stanchfield