Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to rewrite code to optionals?

In my current job we are rewriting some code to Java 8. If you have code like this:

if(getApi() != null && getApi().getUser() != null 
     && getApi().getUser().getCurrentTask() != null)  
{
   getApi().getUser().getCurrentTask().pause();
}

you can simply rewrite it to

Optional.ofNullable(this.getApi())
.map(Api::getUser)
.map(User::getCurrentTask)
.ifPresent(Task::pause);

without changing code behaviour. but what if something in the middle can throw NPE because it is not checked to null?

for example:

if(getApi() != null && getApi().getUser() != null 
     && getApi().hasTasks())  
{
   getApi().getMasterUser(getApi().getUser()) //<- npe can be here
     .getCurrentTask().pause();
}

what is the best way to rewrite code like this using optionals?(it should work exactly the same and throw npe when getMasterUser(...) returns null)

UPD second example:

if(getApi()!=null && getApi.getUser() != null)
{
   if(getApi().getUser().getDepartment().getBoss() != null)// <- nre if department is null
     {
        getApi().getUser().getDepartment().getBoss().somefunc();
     }
 }

it has nullchecks for api, user, boss, but not department. how can it be made using optionals?

like image 701
maxpovver Avatar asked Jul 19 '15 10:07

maxpovver


People also ask

How do optionals work in Java?

Optional is a container object used to contain not-null objects. Optional object is used to represent null with absent value. This class has various utility methods to facilitate code to handle values as 'available' or 'not available' instead of checking null values.

How do I convert optional in Java?

In Java 8, we can use . map(Object::toString) to convert an Optional<String> to a String .

Does Java have optional chaining?

The need for Optional In any Java application, it is a common pattern to use method chaining to de-reference object properties. This often leads to the NullPointerException whenever there is a null object reference.

Is it good to use optional in Java?

By the way, here is how Optional is described in the Java SE 11 documentation: “ Optional is primarily intended for use as a method return type where there is a clear need to represent 'no result,' and where using null is likely to cause errors.

What are the benefits of a code rewrite?

A code rewrite gives you the benefit of experience – you know the weaknesses of the old system, the design flaws, current requirements and future road map. You can plan for it, design a system that will overcome the challenges and plan for the future.

What are the benefits of a complete rewrite of a system?

You incrementally replace parts of the old system, you can still use your E2E and integration tests because the functionality hasn’t changed and the calling code is still in the old system. Another benefit is that you can pause or slow down the rewrite if the business requires it while having the ability to choose any stack you wish.

How to create an optional with a null reference in JavaScript?

You can create an Optional instance that can contain a value by using the of () method. This method provides us the flexibility to create an optional with null or with a non-null reference. Following is the code snippet to create an optional with the null reference.

How to create an optional class in Java?

The optional class has no public constructor and expected to be accessed through the provided static factory methods As discussed, an optional instance can only be created through the factory methods provided in the Optional class. Following are the three factory methods:- You can create an empty instance of Optional by using the empty () method.


1 Answers

if(getApi() != null && getApi().getUser() != null) {
    if(getApi().getUser().getDepartment().getBoss() != null) {
        getApi().getUser().getDepartment().getBoss().somefunc();
    }
}

One way of writing this with optionals is:

Optional.ofNullable(this.getApi())
    .map(Api::getUser)
    .map(user -> Objects.requireNonNull(user.getDepartment()))
    .map(Department::getBoss)
    .ifPresent(Boss::somefunc);

But this is error-prone because it requires the client to keep track of what is and isn't optional. A better way would be to make the api itself return an optional instead of a nullable value. Then the client code is:

this.getApi()
    .flatMap(Api::getUser)
    .map(user -> user.getDepartment().getBoss())
    .ifPresent(Boss::somefunc));

This would make it clearer in the api which values should be optional and make it a compile-time error to not handle them.

if(getApi() != null && getApi().getUser() != null && getApi().hasTasks()) {
    getApi().getMasterUser(getApi().getUser()).getCurrentTask().pause();
}

Here, you need access to api and user at the same time so you probably need to nest the lambdas:

getApi().filter(Api::hasTasks).ifPresent(api -> {
    api.getUser().ifPresent(user -> {
        api.getMasterUser(user).getCurrentTask().ifPresent(Task::pause);
    });
});
like image 197
fgb Avatar answered Oct 05 '22 07:10

fgb