Enum Idiom Question

R

Rhino

I'm trying something Eric Sosman suggested on another thread but I have
doubts about one of the idioms so I thought I'd check here and see if there
was a better way.

A method name pad() returns a special class called PadResult. PadResult is
defined as follows:

import CompletionStatus;


/**

* Simple holder class contains the result of invoking the pad() method.

*

* <p>If the pad() method encounters no errors along the way, it returns a
CompletionStatus set to NO_ERROR and a String containing the

* result of the padding of the input value. If the pad() method encounters
trouble along the way, it returns a CompletionStatus of ERROR

* and an error message.</p>

*/

public class PadResult {


CompletionStatus status;

String result;


public PadResult(CompletionStatus status, String result) {


this.status = status;

this.result = result;

}


public CompletionStatus getStatus() {


return status;

}


public String getResult() {


return result;

}

}



And here is the enum CompletionStatus:



/**

* This enum contains a list of possible completion statuses for methods.

*/

public enum CompletionStatus {


/** Constant for ERROR. */

ERROR,


/** Constant for NO_ERROR */

NO_ERROR;


}





The method is then invoked as follows:

PadResult padResult = PadUtils.pad("Footsy", ' ', 't', 3); //Pad Footsy with
trailing blanks and make the final result 3 characters long

Since this should fail because the requested final length would truncate the
input string, pad() will return CompletionStatus.ERROR and an error message
via PadResult.

I'm checking the value of the CompletionStatus as follows:



if (padResult.getStatus()==CompletionStatus.ERROR) {

System.out.println(padResult.getResult());

}



It's the if statement that concerns me here. This code works fine (I can
test for CompletionStatus.NO_ERROR by simply changlng the right side of the
if) but it doesn't look right. It reminds me of mistakes I made when I was
new to Java comparing Strings to each other via the == operator to see if
they had the same VALUE but discovering that == doesn't determine equality
of value.

I've tried using a switch() statement -

switch(padResult.getStatus()) {

case NO_ERROR:

System.out.println("The padded value is " + padResult.getResult());

break;

default:

System.err.println("Error!! --> " + padResult.getResult());

break;

}

That also works but is a little long for my tastes.



Is there a better way to do this if statement? If so, what is it?
 
J

Jeff Higgins

I'm trying something Eric Sosman suggested on another thread but I have
doubts about one of the idioms so I thought I'd check here and see if there
was a better way.

A method name pad() returns a special class called PadResult. PadResult is
defined as follows:

import CompletionStatus;


/**

* Simple holder class contains the result of invoking the pad() method.

*

*<p>If the pad() method encounters no errors along the way, it returns a
CompletionStatus set to NO_ERROR and a String containing the

* result of the padding of the input value. If the pad() method encounters
trouble along the way, it returns a CompletionStatus of ERROR

* and an error message.</p>

*/

public class PadResult {


CompletionStatus status;

String result;


public PadResult(CompletionStatus status, String result) {


this.status = status;

this.result = result;

}


public CompletionStatus getStatus() {


return status;

}


public String getResult() {


return result;

}

}



And here is the enum CompletionStatus:



/**

* This enum contains a list of possible completion statuses for methods.

*/

public enum CompletionStatus {


/** Constant for ERROR. */

ERROR,


/** Constant for NO_ERROR */

NO_ERROR;


}





The method is then invoked as follows:

PadResult padResult = PadUtils.pad("Footsy", ' ', 't', 3); //Pad Footsy with
trailing blanks and make the final result 3 characters long

Since this should fail because the requested final length would truncate the
input string, pad() will return CompletionStatus.ERROR and an error message
via PadResult.

I'm checking the value of the CompletionStatus as follows:



if (padResult.getStatus()==CompletionStatus.ERROR) {

System.out.println(padResult.getResult());

}



It's the if statement that concerns me here. This code works fine (I can
test for CompletionStatus.NO_ERROR by simply changlng the right side of the
if) but it doesn't look right. It reminds me of mistakes I made when I was
new to Java comparing Strings to each other via the == operator to see if
they had the same VALUE but discovering that == doesn't determine equality
of value.

I've tried using a switch() statement -

switch(padResult.getStatus()) {

case NO_ERROR:

System.out.println("The padded value is " + padResult.getResult());

break;

default:

System.err.println("Error!! --> " + padResult.getResult());

break;

}

That also works but is a little long for my tastes.



Is there a better way to do this if statement? If so, what is it?
<http://www.informit.com/articles/article.aspx?p=433387>
 
A

Arne Vajhøj

I'm trying something Eric Sosman suggested on another thread but I have
doubts about one of the idioms so I thought I'd check here and see if there
was a better way.

A method name pad() returns a special class called PadResult. PadResult is
defined as follows:
public class PadResult {


CompletionStatus status;

String result;

The accessability level of package does not seem right.

public enum CompletionStatus {


/** Constant for ERROR. */

ERROR,


/** Constant for NO_ERROR */

NO_ERROR;


}

The method is then invoked as follows:

PadResult padResult = PadUtils.pad("Footsy", ' ', 't', 3); //Pad Footsy with
trailing blanks and make the final result 3 characters long

Since this should fail because the requested final length would truncate the
input string, pad() will return CompletionStatus.ERROR and an error message
via PadResult.

I'm checking the value of the CompletionStatus as follows:

if (padResult.getStatus()==CompletionStatus.ERROR) {

System.out.println(padResult.getResult());

}

It's the if statement that concerns me here. This code works fine (I can
test for CompletionStatus.NO_ERROR by simply changlng the right side of the
if) but it doesn't look right. It reminds me of mistakes I made when I was
new to Java comparing Strings to each other via the == operator to see if
they had the same VALUE but discovering that == doesn't determine equality
of value.
Is there a better way to do this if statement? If so, what is it?

I would compare with CompletionStatus.NO_ERROR, because it is
a lot more likely that you will have more than one error status
than more than one no error status.

I would seriously consider instead of the enum to have a boolean
plus a String, because true/false and a textual explanation is
really what you need.

If an error is something that warrants an exception then
you could simply the code by using an exception.

Some error situations could even warrant an uncheck
exception (deriving from RuntimException).

Arne
 
R

Rhino

Arne Vajhøj said:
The accessability level of package does not seem right.




I would compare with CompletionStatus.NO_ERROR, because it is
a lot more likely that you will have more than one error status
than more than one no error status.
Okay, that's fair. But am I writing the comparison correctly? That ==
operator looks wrong somehow, even if it works. I'm concerned that this
might be like comparing two Strings with the == operator; sometimes it will
show equality and make you think it is confirming equality of value between
the two strings but it is not; you have to use equals() to compare String
values. But I'm not sure what the equivalent is for an enum.
I would seriously consider instead of the enum to have a boolean
plus a String, because true/false and a textual explanation is
really what you need.

If an error is something that warrants an exception then
you could simply the code by using an exception.

Some error situations could even warrant an uncheck
exception (deriving from RuntimException).
I'm more or less satisfied that the situations I'm trying to handle right
now don't warrant exceptions so I'm trying to work out the coding without
using exceptions. (I've actually got code that throws and catches exceptions
nailed down.)

Thanks for your help, Arne!
 
R

Rhino

Jeff Higgins said:

Interesting article; I wonder if we might call it a "poor man's version" of
the Robust Java book you mentioned earlier :)

The first page is the most interesting for the situation I am trying to
code. He seems to be assuming (in the third example of page 1) that
chargeCustomerCard(variable1, variable2) is returning a boolean and nothing
else. That's fine and I understand the example for that case. But what about
the case where the method is returning something else? For instance, my
pad() method's main output is the string in the first input parameter,
padded out according to instructions in the other parameters. The initial
version of pad() returned only the padded string or threw an exception if
there were problems with the input parameters. But if I'm not going to throw
an exception and _do_ want to return an error message (or even a message
number that could be looked up), I tend to need something like this
PadResult class that I've concocted for this thread so that I can pass back
either an "it worked" and a padded String or an "it failed" and an error
message.

What do you think? Is PadResult or something like it my best alternative
here, assuming we agree that an exception is overkill for a case where an
input parameter is just miscoded?
 
R

Rhino

I would seriously consider instead of the enum to have a boolean
plus a String, because true/false and a textual explanation is
really what you need.
Sorry, I meant to comment on this point too and didn't realize I had missed
it right away....

My little PadResult class started out with a boolean and a string with the
boolean indicating success or failure of the method and the string
containing either an error message or the padded version of the input
string. But when I looked at the invocation of PadResult and saw

PadResult padResult = new PadResult(true, paddedString);

or

PadResult padResult = new PadResult(false, errorMsg);

I found myself a bit challenged to remember if "true" meant "true, the
method produced a good result" or "true, the method found an error". I could
probably just memorize that true means a successful result or use some
boolean constants to make it clearer - see the example below - but I thought
it would be clearer still if I used a well-named enum value so I went with
the enum. But now that I think about it, this would also work well:

public static final boolean METHOD_WORKED = true;
public static final boolean METHOD_FOUND_ERROR = false;

PadResult padResult = new PadResult(METHOD_WORKED, paddedString);

PadResult padResult = new PadResult(METHOD_FOUND_ERROR, errorMsg);

if (padResult.getStatus()) {
//got padded string
}
else {
// found error
}

[Not tested or compiled yet!!]

Of course, the down side to this approach is that I may have to make a
number of these little holder classes, depending on what each one's normal
return value is. I have methods that return Strings but others that return
ints or Sets or Maps or timestamps or etc. etc. and I'll tend to need of
these little classes for each type of return that a method can give.

They're small, simple classes but there will eventually be a number of
them.....
 
A

Arne Vajhøj

Okay, that's fair. But am I writing the comparison correctly? That ==
operator looks wrong somehow, even if it works. I'm concerned that this
might be like comparing two Strings with the == operator; sometimes it will
show equality and make you think it is confirming equality of value between
the two strings but it is not; you have to use equals() to compare String
values. But I'm not sure what the equivalent is for an enum.

== on enums are fine.

Object identity is exactly what is needed.

Arne
 
J

Jeff Higgins

What do you think? Is PadResult or something like it my best alternative
here, assuming we agree that an exception is overkill for a case where an
input parameter is just miscoded?

I'd just throw an StringUtilsException
if I couldn't recover from an illegal argument.
If you need to go all I18N happy use a MessageFormat.

try {
StringUtils.pad()
} catch(StringUtilsException e) {
HandleException(LocalizeExceptionMessage(e))
}
 
J

Jeff Higgins

I'd just throw an StringUtilsException
if I couldn't recover from an illegal argument.
If you need to go all I18N happy use a MessageFormat.

try {
StringUtils.pad()
} catch(StringUtilsException e) {
HandleException(LocalizeExceptionMessage(e))
}
I may be wrong but I don't think that the Apache
StringUtils.rightPad() method throws any exceptions.
It just lets the callers deal with verifying their arguments.

import org.apache.commons.lang.StringUtils;

public class Scratch {

public static void main(String[] args) {
System.out.println(StringUtils.rightPad("Footsy", -1, ' '));
}

}

Yep, prints:
Footsy
 
J

Jean-Baptiste Nizet

Rhino a écrit :
Sorry, I meant to comment on this point too and didn't realize I had missed
it right away....

My little PadResult class started out with a boolean and a string with the
boolean indicating success or failure of the method and the string
containing either an error message or the padded version of the input
string. But when I looked at the invocation of PadResult and saw

PadResult padResult = new PadResult(true, paddedString);

or

PadResult padResult = new PadResult(false, errorMsg);

I found myself a bit challenged to remember if "true" meant "true, the
method produced a good result" or "true, the method found an error". I could
probably just memorize that true means a successful result or use some
boolean constants to make it clearer - see the example below - but I thought
it would be clearer still if I used a well-named enum value so I went with
the enum.

When a constructor's argument are not sufficiently clear, it might be a
good idea to use a factory method instead:

public class PadResult {

private String result;
private String errorMessage;
private boolean successful;

private PadResult(boolean successful, String resultOrErrorMessage) {
this.successful = successful;
if (successful) {
this.result = resultOrErrorMessage;
}
else {
this.errorMessage = resultOrErrorMessage;
}
}

public static PadResult createSuccessfulResult(String result) {
return new PadResult(true, result);
}

public static PadResult createFailedResult(String errorMessage) {
return new PadResult(false, errorMessage);
}

// getters omitted
}

then your pad() method uses

return PadResult.createSuccessfulResult(result);
or
return PadResult.createFailedResult(errorMessage);

and it's much clearer.

JB.
 
R

Rhino

Jeff Higgins said:
I'd just throw an StringUtilsException
if I couldn't recover from an illegal argument.
If you need to go all I18N happy use a MessageFormat.

try {
StringUtils.pad()
} catch(StringUtilsException e) {
HandleException(LocalizeExceptionMessage(e))
}

Fair enough. I'm just looking for alternatives to throwing an exception to
see which approach I like best.

There seems to be a considerably body of opinion that Exceptions are
overkill for relatively minor things like bad input parameters and that they
should be reserved for more severe problems.

I'm trying to keep an open mind on the issue for now....
 
R

Rhino

Jeff Higgins said:
I'd just throw an StringUtilsException
if I couldn't recover from an illegal argument.
If you need to go all I18N happy use a MessageFormat.

try {
StringUtils.pad()
} catch(StringUtilsException e) {
HandleException(LocalizeExceptionMessage(e))
}
I may be wrong but I don't think that the Apache
StringUtils.rightPad() method throws any exceptions.
It just lets the callers deal with verifying their arguments.

import org.apache.commons.lang.StringUtils;

public class Scratch {

public static void main(String[] args) {
System.out.println(StringUtils.rightPad("Footsy", -1, ' '));
}

}

Yep, prints:
Footsy

I'm really not that concerned with padding per se. I just worked with a pad
method for the purposes of exploring options other than exceptions for
handling bad input to a method.

Your specific point _is_ interesting though. I had already thought about
making methods "failproof" by just ignoring bad input and making some sort
of assumption about how they should behave if the input is bad. The
rightPad() method you describe seems to be doing exactly that: if the final
length of the string - I'm guessing that is what the second parameter is in
rightPad() -you could simply ignore it altogether and do something arbitrary
like pretending the user wanted the final length to be the same as the
original length.

I can see where that might be reasonable behaviour in some people's eyes for
some methods. I'm not sure I buy it for a pad() method though. My feeling is
that the person who is trying to use pad() (or rightPad() as the case may
be) had SOMETHING in mind, even if he expressed it in a way that isn't
logical for the method, like asking for a padded string to have a final
length of -1. Now, the method could "second-guess"/reinterpret what he meant
and, in some cases, it might even guess correctly. But it will surely guess
incorrectly a lot of the time too. I would rather notify the user that the
input didn't make sense so that he could ask for something that does make
sense that guess and probably guess wrongly.

Obviously, other developers may feel differently and prefer that the method
make educated guesses about what the user meant, rather than sending him an
error message. I'm fine with that.
 
R

Rhino

Lew said:
This is fully covered in the docs for enums, which you clearly have not
read.

In fact, I _did_ read some Java articles on enums and they did NOT mention
that the == operator was the correct one to use.

Apparently, I read the wrong articles....
 
R

Rhino

Jean-Baptiste Nizet said:
Rhino a écrit :

When a constructor's argument are not sufficiently clear, it might be a
good idea to use a factory method instead:

public class PadResult {

private String result;
private String errorMessage;
private boolean successful;

private PadResult(boolean successful, String resultOrErrorMessage) {
this.successful = successful;
if (successful) {
this.result = resultOrErrorMessage;
}
else {
this.errorMessage = resultOrErrorMessage;
}
}

public static PadResult createSuccessfulResult(String result) {
return new PadResult(true, result);
}

public static PadResult createFailedResult(String errorMessage) {
return new PadResult(false, errorMessage);
}

// getters omitted
}

then your pad() method uses

return PadResult.createSuccessfulResult(result);
or
return PadResult.createFailedResult(errorMessage);

and it's much clearer.

I was starting to think along those lines myself before I saw your post but
was toying with a different approach: one constructor for a successful
result and a different constructor for a problem. I haven't actually tried
writing the code yet to see how much I liked it.

I appreciate your suggestion as another alternative. It looks like it should
work!

Thank you!
 
L

Lew

Rhino said:
There seems to be a considerably body of opinion that Exceptions are
overkill for relatively minor things like bad input parameters and that they
should be reserved for more severe problems.

The dichotomy is not between "minor" and "severe" but between "in band" and
"out of band".

You misconstrue if you think that there is a "minor" or "severe" "problem".

The design decision, and the point of divergence of opinion, is what
constitutes "in" or "out of" band.

If you design that bad inputs are "in band", bad input won't throw an exception.
If you design that bad inputs are "out of band", bad input will throw an
exception. Then you decide between checked and runtime exceptions.

The degree to which the exception propagates, and the decision about in or out
of band, depend in part on how low-level the routine in question is.

There are different strategies for logging, too.

As long as you ask the good questions, e.g., "Is bad input in band or out of
band?", you'll tend make good decisions either way. Bad questions, "Is bad
input minor or severe?", tend to lead to bad decisions either way.
 
R

Rhino

Arne Vajhøj said:
== on enums are fine.

Object identity is exactly what is needed.

Thank you, Arne! I wasn't able to find that idiom anywhere I looked so it's
good to hear I got it right although I expect that was more luck than brains
;-)

By the way, WHERE is that documented? The Enum class in the Java API
includes an equal() method and the tutorials I read about enum and the Sun
site don't mention that idiom at all...
 
L

Lew

In fact, I _did_ read some Java articles on enums and they did NOT mention
that the == operator was the correct one to use.

By "the docs" I'm referring to the JLS and the Javadocs, which are the primary
sources. They don't quite cover everything, but they are canonical as far as
they go.

To whit, the chapter of the language spec that actually defines enums:
<http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.9>
says, in paragraph 2 of the first "Discussion" sidebar,

"Because there is only one instance of each enum constant, it is permissible
to use the == operator in place of the equals method when comparing two object
references if it is known that at least one of them refers to an enum
constant. (The equals method in Enum is a final method that merely invokes
super.equals on its argument and returns the result, thus performing an
identity comparison.)"
 
L

Lew

Thank you, Arne! I wasn't able to find that idiom anywhere I looked so it's
good to hear I got it right although I expect that was more luck than brains
;-)

By the way, WHERE is that documented? The Enum class in the Java API
includes an equal() method

Yes, it does, and if you read the docs there you find:
public final boolean equals(Object other)
telling you that it cannot be overridden and that it "returns true if the
specified object is equal to this enum constant."

From the definition of what an enum is in the language, you know that there
can only be one instance of an enum constant. Ergo, the only way that an
enum's 'equals()' method can return 'true' is if object identity holds, and
therefore the enum's 'equals()' method is functionally equivalent to '=='.

Even without that, you know that the 'equals()' method is safe to use.
 
A

Arne Vajhøj

Thank you, Arne! I wasn't able to find that idiom anywhere I looked so it's
good to hear I got it right although I expect that was more luck than brains
;-)

By the way, WHERE is that documented? The Enum class in the Java API
includes an equal() method and the tutorials I read about enum and the Sun
site don't mention that idiom at all...

That is actually a good question.

I am sure that you can find it in the JLS (Java Language
Specification).

Same in the enum JSR for Java 1.5.

You can also see it if you examine the generated byte code
or look at the source of Enum.java.

Neither should be necessary for such a basic question.

Heavy googling managed to find:

http://java.sun.com/docs/books/tutorial/reflect/special/enumSetGet.html

<quote>
Since the enum constants are singletons, the == and != operators may be
used to compare enum constants of the same type.
</quote>

But that was not obvious.

I am afraid that the answer is that most Java programmers either
use one of the first mentioned methods or know somebody that does.

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Enum String 5
Understanding an Enum Class Declaration 6
enum compareTo() 6
Java matrix problem 3
Extending Enum 3
enum type declaration error 6
Looking for right idiom 8
Enum 1

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top