1

Im kinda new to handling exceptions in Java with Junit, a little guidence would be much appreciated.

What I am trying to do:

  • I surround the creation of the new CustomObject with a try as the user can pass in a String that will not match an enum when we call valueof(). I want to be able to catch an exception here, which I am, though I am told: "A catch statement that catches an exception only to rethrow it should be avoided.". There must be a better way to handle this?

  • If the new object has the correct enum then I call isValidObject, which returns a boolean. If the Integer is not valid then I throw an exception.

  • My test has a @Test(expected = AssertionError.class) and is passing.

Is there a better/cleaner way to use the exceptions?

I have the code below:

private CustomObject getObjectFromString(String objectDataString) {
        if (objectDataString != null) {
            String[] customObjectComponents = objectDataString.split(":");
            try {
                CustomObject singleObject = new CustomObject(EnumObjectType.valueOf(customObjectComponents [0]),
                        Integer.parseInt(customObjectComponents [1]));
                if (isValidCustomObject(singleObject)) {
                    return singleObject;
                } else {
                    throw new IllegalArgumentException("Unknown custom object type/value: " + EnumObjectType.valueOf(customObjectComponents [0]) + ":"
                            + Integer.parseInt(customObjectComponents [1]));
                }
            } catch (IllegalArgumentException e) {
                throw e;
            }

        }

Oh, and if anyone can recommend anything good to read about exception handling, that would be great.

maffo
  • 1,393
  • 4
  • 18
  • 35

1 Answers1

5

A catch statement that catches an exception only to rethrow it should be avoided.". There must be a better way to handle this?

Yes, simply remove the try catch. Your code is equivalent to:

private CustomObject getObjectFromString(String objectDataString) {
    if (objectDataString != null) {
        String[] customObjectComponents = objectDataString.split(":");
        CustomObject singleObject = new CustomObject(EnumObjectType.valueOf(customObjectComponents[0]),
                Integer.parseInt(customObjectComponents[1]));
        if (isValidCustomObject(singleObject)) {
            return singleObject;
        } else {
            throw new IllegalArgumentException("Unknown custom object type/value: " + EnumObjectType.valueOf(customObjectComponents[0]) + ":"
                    + Integer.parseInt(customObjectComponents[1]));
        }
    }
}

That code will throw an IllegalArgumentException if the value passed to your enum.valueOf() is not valid or if your isValidCustomObject method returns false.

Note that it might also throw an IndexOutOfBoundException if the string does not contain a : which you probably want to test before calling customObjectComponents[1]. And it might throw NumberFormatException too.

And you seem to accept a null String as a valid entry, which is probably not a good idea (depends on your use case obviously).

I would probably have written it that way:

private CustomObject getObjectFromString(String objectDataString) {
    Objects.requireNonNull(objectDataString, "objectDataString should not be null");
    String[] customObjectComponents = objectDataString.split(":");
    if (customObjectComponents.length != 2) {
        throw new IllegalArgumentException("Malformed string: " + objectDataString);
    }

    EnumObjectType type = EnumObjectType.valueOf(customObjectComponents[0]);
    try {
        int value = Integer.parseInt(customObjectComponents[1]);
    } catch (NumberFormatException e) {
        throw new IllegalArgumentException(customObjectComponents[1] + " is not an integer);
    }

    CustomObject singleObject = new CustomObject(type, value);
    if (isValidCustomObject(singleObject)) {
        return singleObject;
    } else {
        throw new IllegalArgumentException("Unknown custom object type/value: " + type + ":" + value);
    }
}

And finally, it would probably make sense for the CustomObject's constructor to check whether its arguments are ok or not by itself, instead of having to call a separate isValid method. The last block would then simply be:

    return new CustomObject(type, value);

which would throw an IllegalArgumentException from the constructor if required.

Community
  • 1
  • 1
assylias
  • 321,522
  • 82
  • 660
  • 783
  • 1
    Brilliant answer. Thankyou! Also the link about null handling is probably the most useful thing I have read in a long time. – maffo Nov 14 '12 at 22:51
  • You might like [this other link](http://stackoverflow.com/questions/3881/illegalargumentexception-or-nullpointerexception-for-a-null-parameter). I think the [third most voted answer](http://stackoverflow.com/a/8160/829571) makes most sense and is the standard way of handling null - [this other one](http://stackoverflow.com/a/8196334/829571) confirms it. – assylias Nov 14 '12 at 22:56