Java: Collapsing short "if/else" with simple "return"s and trailing "throw" into a single "return"

StackOverflow https://stackoverflow.com/questions/18827965

Pergunta

Here is some code that is more or less a "daily" pattern:

public static Value getValue() {    
    if ( cond1 ) {
        return val1;
    }
    if ( cond2 ) {
        return val2;
    }
    if ( cond3 ) {
        return val3;
    }
    throw new AnyException();
}

At the very first glance, it seems to be able to collapse into a single return statement preserving short-circuit computation like this:

public static Value getValue() {    
    return cond1 ? val1 :
           cond2 ? val2 :
           cond3 ? val3 :
           throw new AnyException() // it could be a legal piece of code in Java
                                    // if the `throw` statement could be an expression
           ;
}

However, it's not legal, because throw is a statement keyword, not an expression. I've tried the following workaround using a generic method:

// Exceptions.java
// Just pretend to let the compiler think it's not an exception statement
public static <T, E extends Throwable> T exception(E ex) throws E {
    throw ex;
}

...
// Return.java
public static Value getValue() {    
    return cond1 ? val1 :
           cond2 ? val2 :
           cond3 ? val3 :
           Exceptions.<Value, AnyException>exception(new AnyException());
}

The the last line in the return statement looks ugly because:

  • verbose syntax and required type parameterization;
  • a static import directive cannot be used here.

Is there an elegant way to make that code a little nicer? Thanks in advance.

(I still must use Java 6)

EDIT:

Well, three years later, this feature is suprisingly implemented for C# 7.0. I find it really useful and natural, and not complicated. Example:

public string GetFirstName()
{
    var parts = Name.Split(" ");
    return parts.Length > 0
        ? parts[0]
        : throw new InvalidOperationException("No name!");
}

Lucky C# guys.

Foi útil?

Solução

If you used exception outside the conditional operator, then type inference would do the right thing. Here, instead of specifying the type arguments, you can just downcast the result into Value, either locally for exception():

return cond1 ? val1 :
       cond2 ? val2 :
       cond3 ? val3 :
       (Value)exception(new AnyException());

or globally, for the entire conditional expression:

return (Value) (
       cond1 ? val1 :
       cond2 ? val2 :
       cond3 ? val3 :
       exception(new AnyException()));

This is still not gold in terms of elegance, but I think it goes a long way. Note that in this case you can have a static import for exception().

Outras dicas

If you rearrange your lines and add another if statement, you can minimize the amount of lines while still having something that is readable.

if(!(cond1 || cond2 || cond3)) throw new AnyException();
return cond1 ? val1 :
       cond2 ? val2 :
       cond3 ? val3;

I must say that you are overcomplicating things though. Readable code is almost always better than really concise code. In your first example, I immediately see what you're trying to do. In your second example, I actually have to concentrate.

There is another way to throw a generic exception without generics.

// Exceptions.java
// Just pretend to let the compiler think it's not an exception statement
public static <T> T exception(E ex, Class<T> tClass) {
    Thread.currentThread().stop(ex);
    return null;
}

...
// Return.java
public static Value getValue() {    
    return cond1 ? val1 :
           cond2 ? val2 :
           cond3 ? val3 :
           exception(new AnyException(), Value.class); // import static Exception
}

You can also use Unsafe.throwException(e);

int length = 1;
String s = "abc"

return (length == s.length())? length: length+1;

Short hand if else for return function.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top