Better approach on handling unexpected string upon converting it to the enum value I have Grade enum and there is a static method to convert a string value to the particular enum value.

public enum Grade {
    None("N"),
    NotAccepted("-"),
    Accepted("+"),
    Uncertain("?");

    private final String gradeSymbol;

    Grade(String gradeSymbol) {
        this.gradeSymbol = gradeSymbol;
    }

    public String getGradeSymbol() {
        return gradeSymbol;
    }

    public static Grade fromGradeSymbol(final String gradeSymbol) {
        switch (gradeSymbol) {
            case "N":
                return None;

            case "-":
                return NotAccepted;

            case "+":
                return Accepted;

            case "?":
                return Uncertain;

            default:
                throw new IllegalArgumentException("Unexpected grade symbol: " + gradeSymbol);
        }
    }

    @Override
    public String toString() {
        return this.gradeSymbol;
    }
}


My question is, what is better way to handle unexpected grade symbol in the static fromGradeSymbol() method.

Another option I consider is the approach using Optional and returning Optional.empty() instead of throwing IllegalArgumentException.

Like this:

public static Optional&lt;Grade&gt; fromGradeSymbol(final String gradeSymbol) {
    switch (gradeSymbol) {
        case "N":
            return Optional.of(None);

        case "-":
            return Optional.of(NotAccepted);

        case "+":
            return Optional.of(Accepted);

        case "?":
            return Optional.of(Uncertain);

        default:
            return Optional.empty();
    }
}


My thoughts:

Throwing exception looks more logical, because it is being thrown in not expected case, when wrong value has been passed. But throwing exception makes it necessary to catch this exception anywhere where I convert string to the enum.

Use of Optional does not involve exceptions and makes cleaner code, without try-catch construct. But it somehow hides the unexpected input.

Sure, I can assume that every time when Optional does not contain a value we have an unexpected input. But it feels like code smell.

What do you think?
All enumerations have a default valueOf(String) method that throw an IllegalArgumentException so your first idea is coherent.

I would say that it depends (..). It depends of your use cases:


If he conversion would be called form an unsafe (user/api) input, then there are chances that you receive an unexpected symbol. And using Optional will force the developer to handle that case more explicitely. 
If the convesrion is made from a safe input (code/config), then you can live with the exception.


In the book Effective Java  from Joshua Bloch (Addison-Wesley Professional, 978-0134685991) there is a full chapter on that subject (in the 2nd edition):


  Enum types have an automatically generated valueOf(String) method that
  translates a constant’s name into the constant itself.
  
  [..]
  
  The following code
  (with the type name changed appropriately) will do the trick for any enum, so long
  as each constant has a unique string representation: 


// Implementing a fromString method on an enum type
private static final Map&lt;String, Operation&gt; stringToEnum
        = new HashMap&lt;String, Operation&gt;();
static { // Initialize map from constant name to enum constant
    for (Operation op : values())
        stringToEnum.put(op.toString(), op);
    }

// Returns Operation for string, or null if string is invalid
public static Operation fromString(String symbol) {
    return stringToEnum.get(symbol);
}


That chapter (and the whole book) is worth the read: CHAPTER 6 ENUMS AND ANNOTATIONS