I am trying to understand the ifPresent() method of the Optional API in Java 8.
I have simple logic:
Optional<User> user=...
user.ifPresent(doSomethingWithUser(user.get()));
But this results in a compilation error:
ifPresent(java.util.functionError:(186, 74) java: 'void' type not allowed here)
Of course I can do something like this:
if(user.isPresent())
{
doSomethingWithUser(user.get());
}
But this is exactly like a cluttered null check.
If I change the code into this:
user.ifPresent(new Consumer<User>() {
#Override public void accept(User user) {
doSomethingWithUser(user.get());
}
});
The code is getting dirtier, which makes me think of going back to the old null check.
Any ideas?
Optional<User>.ifPresent() takes a Consumer<? super User> as argument. You're passing it an expression whose type is void. So that doesn't compile.
A Consumer is intended to be implemented as a lambda expression:
Optional<User> user = ...
user.ifPresent(theUser -> doSomethingWithUser(theUser));
Or even simpler, using a method reference:
Optional<User> user = ...
user.ifPresent(this::doSomethingWithUser);
This is basically the same thing as
Optional<User> user = ...
user.ifPresent(new Consumer<User>() {
#Override
public void accept(User theUser) {
doSomethingWithUser(theUser);
}
});
The idea is that the doSomethingWithUser() method call will only be executed if the user is present. Your code executes the method call directly, and tries to pass its void result to ifPresent().
In addition to #JBNizet's answer, my general use case for ifPresent is to combine .isPresent() and .get():
Old way:
Optional opt = getIntOptional();
if(opt.isPresent()) {
Integer value = opt.get();
// do something with value
}
New way:
Optional opt = getIntOptional();
opt.ifPresent(value -> {
// do something with value
})
This, to me, is more intuitive.
Why write complicated code when you could make it simple?
Indeed, if you are absolutely going to use the Optional class, the most simple code is what you have already written ...
if (user.isPresent())
{
doSomethingWithUser(user.get());
}
This code has the advantages of being
readable
easy to debug (breakpoint)
not tricky
Just because Oracle has added the Optional class in Java 8 doesn't mean that this class must be used in all situation.
You can use method reference like this:
user.ifPresent(ClassNameWhereMethodIs::doSomethingWithUser);
Method ifPresent() get Consumer object as a paremeter and (from JavaDoc): "If a value is present, invoke the specified consumer with the value." Value it is your variable user.
Or if this method doSomethingWithUser is in the User class and it is not static, you can use method reference like this:
user.ifPresent(this::doSomethingWithUser);
Use flatMap. If a value is present, flatMap returns a sequential Stream containing only that value, otherwise returns an empty Stream. So there is no need to use ifPresent() . Example:
list.stream().map(data -> data.getSomeValue).map(this::getOptinalValue).flatMap(Optional::stream).collect(Collectors.toList());
Related
I have a working method that uses parameter as a lambda expression
private BiConsumer<List<String>, Properties> handleList(Properties p) {
return (list, prop) -> executeSubList(list, prop);
}
For p I'm getting a false positive warning from SonarLint
Unused method parameters should be removed (squid:S1172)
If I change prop to p I'm getting a compile error
Lambda expression's parameter p cannot redeclare another local variable defined in an enclosing scope
Is there a real issue or is it a false positive check when using a method parameter as a lambda parameter?
The issue is real. This method returns a BiConsumer that runs executeSubList on a pair or List<String> and Properties arguments, but does so regardless of p. You could just remove it:
private BiConsumer<List<String>, Properties> handleList() {
// p was never used, and can just be removed -------^
return (list, prop) -> executeSubList(list, prop);
}
The accepted answer is totally correct.
However, another take on solving this problem is to create a Consumer instead of a BiConsumer. The parameter p would then be used as the parameter to executeSubList():
private Consumer<List<String>> handleList(Properties p) {
return (list) -> executeSubList(list, p);
}
Whether this or the solution provided in the accepted answer is the best way to go is dependant on how the surrounding code looks and how the method is to be used.
Im currently doing a side project to validate objects using java 8.
Currently I have this:
An interface that is essencially a rewrite of the java 8 predicate interface:
Then, I created the implementation of that same interface:
And then this class is the result of my validation
The concrete object validation can be found here:
public class ConcreteValidator implements EmployeeValidator {
#Override
public void validate(Employee employee) throws EmployeeException {
ValidatorUtil.notNullString.and(ValidatorUtil.notEmptyString)
.and(ValidatorUtil.stringBetween(1, 100)).test(employee.getFirstName())
.getFieldNameIfInvalid(" Please specify valid firstname ").orElse("");
ValidatorUtil.notNullString.and(ValidatorUtil.notEmptyString)
.and(ValidatorUtil.stringBetween(1, 100)).test(employee.getLastName())
.getFieldNameIfInvalid(" Please specify valid lastname ").orElse("");
ValidatorUtil.notNullString.and(ValidatorUtil.notEmptyString)
.and(ValidatorUtil.stringBetween(3, 100)).test(employee.getEmail())
.getFieldNameIfInvalid(" Please specify valid email ").orElse("");
ValidatorUtil.notNullInteger.and(ValidatorUtil.greaterThanZero)
.and(ValidatorUtil.integerBetween(18, 60)).test(employee.getAge())
.getFieldNameIfInvalid(" Please specify valid age ").orElse("");
}
}
This works fine but what I want to do now is to limit the user to use the notNull verification first, and only after that validation all the methods like notEmpty or greaterThanZero will be available.
I searched for fluent interfaces but don't know if it is the correct way to do it (want to do something like this: https://code-held.com/2019/04/29/robust-builder-pattern/)
To summarise, I want to force the developer to validate if the object is null first and all the other methods go next, something like the chaining of the Stream API in java-8.Here is my customValidations.
You can't, not with how you do your methods: <K> GenericValidation<K> from(Predicate<K> predicate).
By doing so, you tell the developer he can pass any Java expressions: you can't validate the content of the expression at runtime, unlike you want to play with bytecode - which you don't.
You need to enforce this using the compiler, for example:
GenericValidation<K> fromNonNull(Predicate<K> predicate) {
return from(val -> val != null && predicate.test(val));
}
Or using types as shown below:
validateThat(employee.getFirstName()) // return a StringValidator1
.isNotNull() // return a StringValidator2
.isNotEmpty()
.hasLengthBetween(1, 100)
;
StringValidator1 only have isNotNull() and return StringValidator2.
That's how you would enforce the isNotNull() check with the compiler: by returning another type providing more services than the default. Since StringValidator1 does not have isNotEmpty(), then the compiler would generate a compilation error by trying to call it.
You may read AssertJ code for how they do their fluent interface. There are of course other source code being fluent (and I think the most important part of "fluent", is that the compiler and IDE helps you in validating what you are doing).
I have one void method that does something on the object passed as a param
public void someMethod(Object object) {
...
}
and I want to invoke it in other method - but only when the one of the Object attributes is not null.
public void otherMethod(Number number) {
repository.findObject(number)
.filter(o -> o.getAttributeOne().isPresent())
.ifPresent(o -> performThirdMethod(o));
}
I want to make sure that performThirdMethod() will be only invoked when one of the object attribute (attributeOne) is NOT null.
Is above method correct? I also wonder what would be the best way to test if this actually works?
In other words - how (in Java8) I can filter the result to see if the attribute is present - if in one method I am passing a whole object and want to check only one attribute presence that belongs to it?
From the Javadoc of Optional.ifPresent(Consumer)
If a value is present, performs the given action with the value, otherwise does nothing.
Since it's a lambda o -> performThirdMethod(o), not a direct invocation of performThirdMethod, you are given a guarantee that the method "will be only invoked when one of the object attribute (attributeOne) is NOT null".
I also wonder what would be the best way to test if this actually works?
I use a debugger with a breakpoint inside a lambda. You also can log a message before calling performThirdMethod.
.ifPresent(o -> {
System.out.println("performThirdMethod will be executed");
performThirdMethod(o);
});
Since Java 9, there is ifPresentOrElse(Consumer,Runnable) to perform a empty-based action if no value is present.
.ifPresentOrElse(
o -> performThirdMethod(o),
() -> System.out.println("performThirdMethod won't be executed")
);
I have a class that, in essence, looks like this:
class Checkpointer {
public <Input,Output> Output runFunction(Input input, Function<Input,Output> function) {
Output output;
// Sometimes run the function, sometimes return an Output from a cache
return output
}
}
I would like to mock this class using Mockito doAnswer:
Checkpointer checkpointer; // mocked via #Mock annotation
Mockito
.doAnswer(/* ??? */)
.when(checkpointer)
.runFunction(Mockito.any(), Mockito.any());
The function I want to mock needs to be generic. Can this be done?
For example, my first attempt produced the following. Not only did I resort to Object as the type arguments for Function, but the compiler was still unhappy with unchecked casting:
Mockito.doAnswer((invocation) ->
{
// compiler is not happy with this cast V
Function<Object,Object> function = (Function<Object,Object>)invocation.getArguments()[1];
return function.apply(invocation.getArgument(0));
}).when(checkpointer).runFunction(Mockito.any(), Mockito.any());
If this can't be done, I think can try writing my own mock class extending the first and use Mockito.spy.
The problem here is that you insist on using getArguments, which returns an Object[]
Since you know the index of the Function argument, you can use getArgument(index), as you're doing the line after that.
final Function<String, String> argument = invocation.getArgument(1);
Is this what you're looking for? Type inference for the getArgument generic type is working fine.
If not, can you provide a more elaborate example?
I'm learning SpringBoot2.0 with Java8.
And I followed some blog-making tutorial example.
The tutorial source code is:
#GetMapping("/{id}/edit")
public String edit(#PathVariable Long id, Model model) {
model.addAttribute("categoryDto", categoryService.findOne(id));
return "category/edit";
}
But this code is throwing this error:
categoryService.findOne(id)
I'm thinking about changing the JPA findOne() method to Optional< S >
How to solve that?
More info:
This is the categoryService method:
public Category findOne(Long id) {
return categoryRepository.findOne(id);
}
From at least, the 2.0 version, Spring-Data-Jpa modified findOne().
Now, findOne() has neither the same signature nor the same behavior.
Previously, it was defined in the CrudRepository interface as:
T findOne(ID primaryKey);
Now, the single findOne() method that you will find in CrudRepository is the one defined in the QueryByExampleExecutor interface as:
<S extends T> Optional<S> findOne(Example<S> example);
That is implemented finally by SimpleJpaRepository, the default implementation of the CrudRepository interface.
This method is a query by example search and you don't want that as a replacement.
In fact, the method with the same behavior is still there in the new API, but the method name has changed.
It was renamed from findOne() to findById() in the CrudRepository interface :
Optional<T> findById(ID id);
Now it returns an Optional, which is not so bad to prevent NullPointerException.
So, the actual method to invoke is now Optional<T> findById(ID id).
How to use that?
Learning Optional usage.
Here's important information about its specification:
A container object which may or may not contain a non-null value. If a
value is present, isPresent() will return true and get() will return
the value.
Additional methods that depend on the presence or absence of a
contained value are provided, such as orElse() (return a default value
if value not present) and ifPresent() (execute a block of code if the
value is present).
Some hints on how to use Optional with Optional<T> findById(ID id).
Generally, as you look for an entity by id, you want to return it or make a particular processing if that is not retrieved.
Here are three classical usage examples.
Suppose that if the entity is found you want to get it otherwise you want to get a default value.
You could write :
Foo foo = repository.findById(id)
.orElse(new Foo());
or get a null default value if it makes sense (same behavior as before the API change) :
Foo foo = repository.findById(id)
.orElse(null);
Suppose that if the entity is found you want to return it, else you want to throw an exception.
You could write :
return repository.findById(id)
.orElseThrow(() -> new EntityNotFoundException(id));
Suppose you want to apply a different processing according to if the entity is found or not (without necessarily throwing an exception).
You could write :
Optional<Foo> fooOptional = fooRepository.findById(id);
if (fooOptional.isPresent()) {
Foo foo = fooOptional.get();
// processing with foo ...
} else {
// alternative processing....
}
The method has been renamed to findById(…) returning an Optional so that you have to handle absence yourself:
Optional<Foo> result = repository.findById(…);
result.ifPresent(it -> …); // do something with the value if present
result.map(it -> …); // map the value if present
Foo foo = result.orElse(null); // if you want to continue just like before
Indeed, in the latest version of Spring Data, findOne returns an optional. If you want to retrieve the object from the Optional, you can simply use get() on the Optional. First of all though, a repository should return the optional to a service, which then handles the case in which the optional is empty. afterwards, the service should return the object to the controller.
I always write a default method "findByIdOrError" in widely used CrudRepository repos/interfaces.
#Repository
public interface RequestRepository extends CrudRepository<Request, Integer> {
default Request findByIdOrError(Integer id) {
return findById(id).orElseThrow(EntityNotFoundException::new);
}
}
Optional api provides methods for getting the values. You can check isPresent() for the presence of the value and then make a call to get() or you can make a call to get() chained with orElse() and provide a default value.
The last thing you can try doing is using #Query() over a custom method.
The findOne method of the CrudRepository interface has been replaced by findById since version 2.0 of Spring Data Commons.
you replace findOne(id) by:
findById(id).orElse(null)
Consider an User entity and UserRepository. In service package code like below.
Optional<User> resultUser = UserRepository.findById(userId); //return Optional
User createdUser = resultUser.get(); //return User
Now you can access all the User entity attributes using getter.
createdUser.getId();
createdUser.getName();
like that.