Java Optional <T> question, am I doing this right?

I had a "bad habit" of throwing null

at places like enumerators when something doesn't exist.

Example:

private enum Foo {
    NULL(1, null, 2),
    NOT_NULL(3, new Bar(), 4);

    private int a, c;
    private Bar b;

    Foo(int a, Bar b, int c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }
}

      

So now I'm trying to convert my code to use Optional<T>

As everyone suggests, but I'm not sure if I'm doing it right.

Here's my code (Trimmed enum):

public static enum Difficulty { 
    EASY, MEDIUM, HARD
}

public static enum SlayerTasks {
    NONE(0, Optional.empty(), Optional.empty(), Optional.empty()),
    NPC(1, Optional.of(Difficulty.EASY), Optional.of("That one place."), Optional.of(1));

    private int taskId;
    private Optional<Difficulty> difficulty;
    private Optional<String> location;
    private Optional<Integer> npcId;

    SlayerTasks(int taskId, Optional<Difficulty> difficulty, Optional<String> location, Optional<Integer> npcId) {
        this.taskId = taskId;
        this.difficulty = difficulty;
        this.location = location;
        this.npcId = npcId;
    }

    public int getTaskId() {
        return taskId;
    }

    public Difficulty getDifficulty() {
        return difficulty.get();
    }

    public String getLocation() {
        return location.get();
    }

    public int getNpcId() {
        return npcId.get();
    }
}

      

What worries me is the documentation related to #get()

found here where it states:

If a value is present in this Optional, it returns a value, otherwise a NoSuchElementException is thrown.

So, I figured that to prevent this, I would wrap the getter in #isPresent()

, but then I couldn't figure out how to return empty.

Is this the correct way to do something, or am I missing something? I am not looking for "Fix", I am looking for information on efficiency and good practice.

+3


source to share


3 answers


You need to ask yourself what you want your getter to do if nothing is returned.

There are only four options:



  • Returns zero (but then you are back to what you were trying to avoid);
  • Let your recipient return Optional<T>

    instead T

    ;
  • Returns the default value if nothing is set;
  • Throw an exception.

I would go with 2 if it wasn't for a very clear correct answer to what should be the default. 4 is only suitable if the client code always needs to know if there is something in there and only ask it if there is (which would be unusual, though not impossible).

+4


source


You can replace location.get()

with location.orElse("SomeDefaultValue")

if you want to avoid the exception. This allows you to return the default value if Optional is empty.



+2


source


IMO, if you are implementing your logic with a "maybe" monad (optional values), you should stick with the optional object and cast it, fetching the wrapped value only if necessary.

To change the invalid value, you can use methods Optional.ifPresent()

, Optional.map()

or Optional.flatMap()

for example

Optional<Difficulty> difficulty = NPC.getDifficulty();
difficulty.ifPresent(diff -> { /* do comething here ... */ });

      

+1


source







All Articles