I am trying to understand and use Java 8 - Optional feature. I would like to refactor this code block. Without Optional I have such a condition.
ClassA objA = findObject();
if(objA == null || objA.isDeleted()){
throw Exception("Object is not found.");
}
I want to transform this block using Optional wrapper. I have read about filter, ifPresent functions but I could not find a way. Maybe it is simple but I am new to Java 8. I would appreciate if you could help.
You shouldn't use Optional<T> to solely replace the if statement as it's no better and doesn't gain you any benefit. A much better solution would be to make the findObject() method return Optional<ClassA>.
This makes the caller of this method decide what to do in the "no value" case.
Assuming you've made this change, you can then leverage the Optional<T> type:
findObject().filter(a -> !a.isDeleted()) // if not deleted then do something
.map(...) // do some mapping maybe?
... // do some additional logic
.orElseThrow(() -> new Exception("Object is not found."));//if object not found then throw exception
see the Optional<T> class to familiarise your self with the API and the methods that are available.
#Eric as you mentioned in your comment, if you don't want (can't) change the return type of findObject() for some constraints, you can do the following :
ClassA objA = findObject();
Optional<ClassA> myOpt =
Optional.ofNullable(objA)
.filter(e->!e.isDeleted())
.orElseThrow(()->new Exception("Object is not found.");
return list.stream()
.filter(tmm -> tmpAddress.type() == 1)
.findFirst()
.orElseThrow(()->{
logger.error("ERROR");//something like this
exceptionHandler.handler("some exception
return null;
});
Related
I want to set a value to a string if an Optional is present else get it from a list based on a condition. I have tried many ways but not able to get it. I am new to Streams so need help.
Basically my condition is this in traditional way -
String rel = ""
if(release.isPresent()){
rel = release.get();
}
else{
for(Release r: project.getReleases()){
if(r.isActive() == true){
rel = r.getName();
}
}
}
This is what I have written, but it doesn't work. I am getting error in the orElse part -
rel = release.ifPresent(r-> release.get())
.orElse(
project.getReleases()
.stream()
.filter( r -> r.isActive() == true)
.findFirst()
.map(r->r.getName()));
Can you please suggest what is the correct way to do this ? Thanks in advance for any help.
This is what you want in case you use java-9 or newer (I recommend you to tag the version used):
String rel = release
.or(() -> project.getReleases().stream()
.filter(Release::isActive)
.map(Release::getName)
.findFirst())
.orElse("");
Basically Optional#or returns either the present value from the original Optional or provides a Supplier<Optional> providing such value in lazy way (will not be called in case the former value is present).
Use the advantage that Stream#findFirst returns Optional hence such call is compatible with the method needs. Finally call orElse("") as the last possible value if no usable value was present in the previous attempts.
You should use Optional#orElseGet for this
Why orElseGet and not orElse ?
Because orElseGet accepts a Supplier which will only be invoked if your Optional is empty. So you won't have the overhead of Stream creation etc.
Example
String rel = release.orElseGet(() -> project.getReleases()
.stream()
.filter(Release::isActive)
.map(Release::getName)
.findFirst()
.orElse(""));
you can do
release.orElse(project.getReleases()
.stream().filter(Release::isActive).findFirst().map(Release::getName).orElse(""));
I have came across this code.
public AnimalResponse getAnimal(Specie specie) {
AnimalEntity animal = speciesRepository.findBySpecie(specie).orElseThrow(
() - > new ResourceNotFoundException(specie)
).getAnimal();
if (animal == null) {
throw new NoAnimalException();
}
return getAnimal(animal.getId());
}
getAnimal() method may return null, so later on invoking getId() on that object leads to NPE. Hence null check is used that I want to avoid.
I was wondering: how can I re-write this method for it to use Optionals and maintain the same functionality? Is it doable, will it be cleaner?
I realize this method is confusing at best, but I don't want to change anything outside this method, and struggle to make anything out of Optional work.
trdanv's answer is about as good as it gets without changing the behaviour.
If you are able to consolidate the two exceptions into one which covers either Animal being null or species not being found, then you are able to use Optional much more idiomatically
return speciesRepository.findBySpecie(specie)
.map(Species::getAnimal)
.map(AnimalEntity::getId)
.map(this::getAnimal)
.orElseThrow(() -> new AnotherException(specie));
Basically my ideal is we map species to animal before we throw exception
AnimalEntity animal = speciesRepository.findBySpecie(specie)
.map(spec -> spec.getAnimal())
.orElseThrow(() -> new ResourceNotFoundException(specie));
return getAnimal(animal.getId());
If I understand correctly, you can wrap it in a Optional.ofNullable() like so:
public AnimalResponse getAnimal(Specie specie) {
AnimalEntity animal = Optional.ofNullable(speciesRepository
.findBySpecie(specie)
.orElseThrow(() - >
new ResourceNotFoundException(specie))
.getAnimal())
.orElseThrow(() - > new NoAnimalException());
return getAnimal(animal.getId());
}
Is it possible to return the Optional value from method only if it's present, but if it's not just continue with a normal method flow. Something like this:
public Message processMessage(Message message) {
// ErrorMessage is subclass of Message; only returned if validator found some violations, otherwise empty optional
Optional<ErrorMessage> error = validator.validate(message);
if (error.isPresent()) return error.get();
// returns different possible subclasses of Message
return service.processMessage(message);
}
Is there any prettier way to write this?
Your problem is indeed that the return types do not match. orElseGet only works when the supplier returns a subtype of the Optional type.
To work around this, you can force a cast to the parent type first:
return error.<Message>map(m -> m).orElseGet(() -> service.processMessage(message));
or equivalently:
return error.map(m -> (Message) m).orElseGet(() -> service.processMessage(message));
I simply would go with Optional.orElseGet and an explicit cast in between:
public Message processMessage(final Message message) {
return validator.validate(message)
.map(Message.class::cast)
.orElseGet(() -> service.processMessage(message));
}
I am not able to test it currently but it may give u an idea, may be you can implement something like below
return Optional.ofNullable(message)
.map(validator::validate)
.orElseGet(service::processMessage)
Looking at that snippet, it looks like the validate method on the validator doesn't quite have the proper return type. Consider using e.g. io.vavr.control.Either or io.vavr.control.Validation monad. Take a look at a possible signature for validate:
Either<SpecificError, ? extends Message> validate(Message message);
Now the map and fold combinators can be used like so:
validator
.validate(message)
.map(message -> service.processMessage(message))
.fold(error -> new ErrorMessage(error), success -> success); // the left function can be replaced by Function.identity()
to yield Message.
I have the following code repeated to a lots of places. I would like to know if there is any common practice in Java to define such repetitive code by usage of interface/functional interface/abstract class. The inside logic for if is different but out if else and log is same for all.
Optional<ABC> factory = factoryResolver.resolve(XYZ);
if (factory.isPresent()) {
// Logic varies here
return X;
} else {
LOGGER.error("Some logs");
}
return Y;
What you are doing is essentially no different from using null checks, but in a way that is more opaque and verbose.
A more object-oriented solution would be to take advantage of polymorphism. Rather than returning an Optional<ABC>, return an ABC directly. If no ABC can be resolved for XYZ, you can return an UnresolvedABC class which implements the ABC interface in a way that makes sense (e.g. throws exceptions or logs errors).
For more details, see the Null Design Pattern (Wikipedia)
You can eliminate if using Optional.orElseGet
Optional<ABC> factory = factoryResolver.resolve(XYZ);
return factory.map((abc) -> X).orElseGet(() -> {
LOGGER.error("Some logs");
return Y;
});
You should not create local variable here, it's of no use.
factoryResolver.resolve(XYZ)
.map(x -> X) //Your logic
.orElseGet(() -> {
LOGGER.error("Some logs");
return Y.
});
I am refactoring the code to Java 8 and I want to replace null checks with Optional.
public Employee findEmployeeById(String id) {
List<Employee> empList = .. //some db query
return (empList.isEmpty() ? null : empList.get(0));
}
Optional.ofNullable(empList.get(0)) won't work as when it will throw IndexOutofBoundException
Or should I ideally replace null with Optional.empty()?
As #Jesper already mentioned in the comments, you have to check whether the list is empty and then return an empty Optional.
public Optional<Employee> findEmployeeById(String id) {
List<Employee> empList = .. //some db query
return empList.isEmpty() ? Optional.empty() : Optional.of(empList.get(0));
}
An Optional is a wrapper around a potentially null value that allows you to avoid explicitly checking for null when you use it.
Have a look at the Optional documentation to see what functionality it provides.
For example you can get an employee's name or "unknown" if it's absent, without checking for null:
Optional<Employee> emp = findEmployeeById(id);
String name = emp.map(Employee::getName).orElse("unknown");
You may read this post about Uses for Optional to see if it makes sense for you to use Optional.
To me the natural solution would be to keep your ? : construct as in Floern’s answer. If, however, you want to get rid of that, there is also an elegant solution without it:
public Optional<Employee> findEmployeeById(String id) {
List<Employee> empList = .. //some db query
return empList.stream().findFirst();
}
This gives you what you want because findFirst() returns an Optional. If you don’t care which element you get — or you know there’s never more than one — you may alternatively use findAny(), it too returns an Optional.
Why don't you simply replace your method with:
public Optional<Employee> findEmployeeById(String id) {
List<Employee> empList = .. //some db query
return (empList.isEmpty() ? Optional.empty() :
Optional.ofNullable(empList.get(0)));
}
I suggest you wrap the empList.get(0) in a Optional.ofNullable in case it might still be null.
As far as why that is better: think about the caller of the method. Whomever is now calling your method has to think what to actually do when the result is empty.
Besides you are now forced into writing code like:
Optional<Employee> emp = findEmployeeById("12");
if (emp.isPresent()) {
} else {
....
}
You can also chain this to become more fluent like:
emp.orElseThrow(RuntimeException::new)
Or other Optional methods.
That is simply not the case when you return an Employee. You are not even thinking (usually) to check if the reference is null.
That makes your code less error-prone and easier to understand.
Another possibility would be to do it as follows:
return Optional.of(empList).filter(list -> !list.isEmpty()).map(list -> list.get(0));
This will automatically return an empty Optional in case the list is empty or empList.get(0) returns null.
If empList can be null, consider using Optional.ofNullable(empList) instead of Optional(empList).