In Optional while optional.orElse method is call, irrespective of the element is present or not the orElse part is executed it does not behave as the if else condition.
In the below code if you see in Case 1 both getNullPoJo and getDefaultPoJo is executed since getNullPoJo will return empty Optional
In Case 2 where you will get a Optional with loaded value (from getLoadedPoJo) also you getDefaultPoJo is executed
I am just trying to understand the working of optional.orElse.
public static void main (String [] a) {
PoJo poJo1=getNullPoJo().orElse(getDefaultPoJo());//Case 1
System.out.println("pojo1 Got "+poJo1.getVariable());
PoJo poJo2=getLoadedPoJo().orElse(getDefaultPoJo());//Case 2
System.out.println("pojo2 Got "+poJo2.getVariable());
}
private static Optional<PoJo> getNullPoJo() {
System.out.println("Executing getNullPoJo");
Optional<PoJo> optional=Optional.empty();
return optional;
}
private static Optional<PoJo> getLoadedPoJo() {
System.out.println("Executing getLoadedPoJo");
PoJo poJo =new PoJo();
poJo.setVariable("Loaded");
Optional<PoJo> optional=Optional.of(poJo);
return optional;
}
private static PoJo getDefaultPoJo() {
System.out.println("Executing getDefaultPoJo");
PoJo poJo =new PoJo();
poJo.setVariable("Default");
return poJo;
}
The current Output is:
Executing getNullPoJo
Executing getDefaultPoJo
pojo1 Got Default
Executing getLoadedPoJo
Executing getDefaultPoJo
pojo2 Got Loaded
My Expected Output is:
Executing getNullPoJo
Executing getDefaultPoJo
pojo1 Got Default
Executing getLoadedPoJo
pojo2 Got Loaded
I do not want the call to getDefaultPoJo in Case 2
Use orElseGet() to avoid evaluating getDefaultPoJo() when the Optional is not empty:
PoJo poJo1=getNullPoJo().orElseGet(() -> getDefaultPoJo());
PoJo poJo2=getLoadedPoJo().orElseGet(() -> getDefaultPoJo());
getNullPoJo().orElse(getDefaultPoJo());
It's a method chain, and every method in this chain will get executed, no matter how the underlying API is supposed to work.
1) getNullPoJo()
2) r = getDefaultPoJo()
3) orElse(r)
In order to execute a method, its actual parameters must be evaluated. To call orElse(getDefaultPoJo()), getDefaultPoJo() must be invoked as well. That's the reason you are getting more than you expected.
Usually, you will see
.orElse(null);
.orElse(defaultValue);
where null, and defaultValue are predefined values that don't require any calculations.
On the other hand, we write
.orElseGet(() -> generateDefaultValue());
.orElseGet(() -> calculateDefaultOutcome());
where generateDefaultValue and calculateDefaultOutcome are methods that do perform some calculations (intensive ones or ones we don't want to execute until the right moment [your case]).
Compare,
.orElseGet(() -> createDefaultPoJo());
.orElse(DEFAULT_POJO);
where DEFAULT_POJO is a variable initialised prior to this method call, and createDefaultPoJo() is a method that creates a default instance every time it gets called.
The output is correct, Optional.orElse() will allways execute the else-action. (the expression you provide) Use orElseGet() -which only calls the function if Optional.isPresent == false- for your desired output:
Difference between `Optional.orElse()` and `Optional.orElseGet()`
https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#orElseGet-java.util.function.Supplier-
Related
I have a function returning an Either<MyError, String> (function2) , which result depends on another function returning another Either<MyError, SomethingElse> (function1)
Both functions rely on a Try block that could fail, and I want to compose those two first function to create a "handle" which will be the main function of my class.
There are basically 3 scenarios possible :
function1 fails : I want handle to return the error given by function1
function1 succeeds and function2 fails : function2 must return its own error then returned by handle
both functions work : handle must return the String
Here is my current code :
private Either<MyError, Path> getPath(Arg arg) { // function 1
return Try.of(() -> //some code that can fail)
.toEither().mapLeft(e -> new MyError("Error message for function1", e));
}
private Either<MyError, String> getContent(Path path) { // function 2
return Try.of(() -> //some code that can fail)
.toEither().mapLeft(e -> new MyError("Error message for function2", e));
}
public Either<MyError, String> handle(Arg arg) {
return Either.right(arg)
.map(this::getPath)
.map(this::getContent);
}
Everything works except the Handle function, I think that my problem might be related to the use of Either::map function, that might not be the thing for my case.
Any thought about this ?
Also, sorry if the answer seems obvious, i am quite new to functionnal programming and vavr.
The method that could help to make this work would be flatMap.
So if you use flatMap instead of map, the handle method will become something like:
public Either<MyError, String> handle(Arg arg) {
return Either.<MyError, Arg>right(arg)
.flatMap(this::getPath)
.flatMap(this::getContent);
}
The scenarios you mentioned are all covered with this flatMap method.
See the Either.flatMap documentation for the official docs about it.
This question already has answers here:
java.util.NoSuchElementException: No value present even though we use stream
(2 answers)
Closed 9 months ago.
While filtering through a list of user defined class type using Stream API has been encountered some cases where no element has been found in the list for given condition.
How to prevent exception in such case and handle according to business logic using optional class?
Stream API method looks like :
public static Optional<Policy> getPolicy(ReturnTermPolicy policyType,
String policyKey) {
Optional<Policy> policy = Optional.of(policyType.getPolicies().stream()
.filter(temp -> temp.getPolicyKey().equals(policyKey))
.findFirst().get());
return policy;
}
The calling code looks like that:
Optional<Policy> updatedPolicyOptional = getPolicy(updatedPolies,policykey); // <- exception is being generated here
if (updatedPolicyOptional.isPresent()) {
// business logic
}
else {
// business logic
}
Output :
Verify audit report for update made in TC_08
java.util.NoSuchElementException: No value present
at java.util.Optional.get(Optional.java:135)
There's no need to extract the result from the optional object just in order to wrap it with an optional again.
It's pointless and will trigger NoSuchElementException if result is not present. To solve the problem, remove the call of get() which both unsafe and redundant in this case:
public static Optional<Policy> getPolicy(ReturnTermPolicy policyType,
String policyKey) {
return policyType.getPolicies().stream()
.filter(temp -> temp.getPolicyKey().equals(policyKey))
.findFirst();
}
In order implement your conditional logic fluently you can make use of Optional.ifPresentOrElse() which expects a Consumer that would be executed if result is present and a Runnable that will be fired in case if optional is empty. Note, this method is accessible with Java 9.
getPolicy(updatedPolies,policykey).ifPresentOrElse(policy -> doSomething(policy),
() -> doSomethingElse());
With Java 8 you can use Optional.ifPresentOrElse() that expects consumer and can cave the if part of conditional logic. And for the case of empty optional, you will need a condition.
Optional<Policy> policy = getPolicy(updatedPolies,policykey);
policy.ifPresentOrElse(policy -> doSomething(policy));
if (!policy.isPresent()) doSomethingElse();
findFirst() already returns an Optional, trying to get() it leads to an error when it is empty. So your function should be:
public static Optional<Policy> getPolicy(ReturnTermPolicy policyType,
String policyKey) {
return = policyType.getPolicies().stream()
.filter(temp -> temp.getPolicyKey().equals(policyKey))
.findFirst();
}
And depending on your Java version (and your business logic) you can use things like:
Java 8.
if (updatedPolicyOptional.isPresent()) {
// business logic
}
else {
// business logic
}
or
T value = updatedPolicyOptional(mapToTFunctor).orElse(someTValue);
Java 9.
updatedPolicyOptional.ifPresentOrElse(someConsumer,someNoParamFunctor);
This question already has answers here:
Difference between `Optional.orElse()` and `Optional.orElseGet()`
(9 answers)
When I need to use Optional.orElseGet() over Optional.orElse()
(3 answers)
Closed 2 years ago.
I was playing with Java's Optional and thought that it works like an if else block. But in the following code even if the name variable is not null the content of the orElse block get's executed. Any explanation?
import java.util.Optional;
class Scratch {
public static void main(String[] args) {
String name = "some text";
System.out.println(
Optional.ofNullable(name)
.map(n -> mapped())
.orElse(getOrElse()));
}
static String mapped(){
System.out.println("mapped -- block executed");
return "mapped";
}
static String getOrElse(){
System.out.println("orElse -- block executed");
return "orElse";
}
}
Output:
mapped -- block executed
orElse -- block executed
mapped
Have a closer look at Optional.orElse(T). It takes a value which needs to be provided to that call but that value will only be returned in the else case. So getOrElse() will be executed to get that value in any case.
Optional.orElse(T) is normally used with already existing values, e.g. like this: map(e -> mapped()).orElse("not found")
If you want to use a function that will only be called in the else case you need to use Optional.orElseGet(Supplier<? extends T>) like this: map(e -> mapped).orElseGet(Scratch::getOrElse) (or orElseGet(() -> getOrElse())).
the orElse part is not being executed. Your getOrElse method is being executed in order to pass a value into orElse, but when the Optional is evaluated the orElse branch isn't retruned.
If you want to lazily evaluate it, you could use orElseGet and pass a method reference to it:
Optional.ofNullable(name)
.map(n -> mapped())
.orElseGet(Scratch::getOrElse));
I am very new to Project reactor library and reactive programming with Kotlin, and trying to implement functions like flatmap, flatMapIterable, subscribe etc.
Now issue is I am trying to use the o/p of one function into another one using flatMapIterable, and after using I am trying to subscribe this, by passing the output of fist function and second one to another function of new class.
Now when I try to use the o/p of function 1, I am unable to see the value, I only see Mono<> or Flux<>.
Below is code snippet for more explanation
var result = employerService.getEmployee("Active") // return value is Mono<GetEmployeeStatusListResult>
result.flatMapIterable(GetEmployeeStatusListResult::emps)
.flatMap {
employerService.getUsersById(it.userId) // it is of type GetEmployeeStatusListResult.emps and value returned from employerService.getUsersById(it.userId) is of type GetUserResult class created
}.subscribe {
aService.createContact(result, it)
}
Now at line 4 I am getting expected userId out of it.userId, but when I inspect result at line 6, then I do not get the expected list of values, it just provides me MonomapFuesable, with mapper and source.
Can anyone please help me to understand what should I do, as my whole agenda is to pass the calculated value from line 1 and line 4 to line 6 function.
Please ask more question, if I haven't provided the required information, I am very new to this.
Thanks in advance !!
[UPDATE] : I have resolved the issue with the following way :
```
employerService.getEmployee("Active") // return value is Mono<GetEmployeeStatusListResult>
.flatMapIterable(GetEmployeeStatusListResult::emps)
.flatMap {
employerService.getUsersById(it.userId).map{x->Pair(it,x)} // it is of type GetEmployeeStatusListResult.emps and value returned from employerService.getUsersById(it.userId) is of type GetUserResult class created
}.subscribe {
aService.createContact(it.first, it.second)
}
```
It's a bit hard to know for sure from the information supplied above, but I think it looks like the call to employerService.getUsersById isn't returning a Publisher. From your comments I'm guessing it's returning an actual value, GetUserResult, rather than a Mono. Below is a mocked up set of classes which show the desired result, I believe. Maybe compare the below to what you've got and see if you can spot a difference?
data class Employee(val userId: String)
data class GetEmployeeStatusListResult(val emps: List<Employee>)
data class GetUserResult(val employee: Employee)
class EmployerService {
fun getEmployee(status: String) = Mono.just(GetEmployeeStatusListResult(listOf(Employee("a"))))
fun getUsersById(userId: String) = Mono.just(GetUserResult(Employee("a")))
}
fun test() {
val employerService = EmployerService()
employerService
.getEmployee("Active")
.flatMapIterable(GetEmployeeStatusListResult::emps)
.flatMap {
employerService.getUsersById(it.userId)
}.subscribe {
// Here "it" is a GetUserResult object
}
}
If, in the subscribe, you need both the initial value retrieved from the call to getEmployee and also the result of the call to getUsersById then you could wrap those two values in a Pair as shown below:
employerService
.getEmployee("Active")
.flatMapIterable(GetEmployeeStatusListResult::emps)
.flatMap { emp ->
employerService.getUsersById(emp.userId).map { emp to it }
}.subscribe {
// Here "it" is a Pair<Employee, GetUserResult>
}
employerService.getEmployee("Active") // return value is Mono<GetEmployeeStatusListResult>
.flatMapIterable(GetEmployeeStatusListResult::emps)
.flatMap {
employerService.getUsersById(it.userId).map{x->Pair(it,x)} // it is of type GetEmployeeStatusListResult.emps and value returned from employerService.getUsersById(it.userId) is of type GetUserResult class created
}.subscribe {
aService.createContact(it.first, it.second)
}
Adding pair function to fetch both the values and use it in subscribe block !!
Thanks everyone !!
I get the following error
[ERROR] AccountServiceResource.java:[165,38] incompatible types: bad return type in lambda expression
[ERROR] Response<okio.ByteString> cannot be converted to java.util.concurrent.CompletionStage<Response<okio.ByteString>>
about the following line
return checkExceptionCauses(exception);
where checkedExceptionCauses is a method that returns a Response<ByteString>
private Response<ByteString> checkExceptionCauses(Throwable exception) {
// ...
}
The question, is why it trying to convert it to a CompletionStage<> all of a sudden? Here's (a simplified version of) the original code that compiled fine:
private CompletionStage<Response<ByteString>> getAccountById(RequestContext rc) {
return accountServiceClient.getAccount().thenApply( getAccountResponse -> {
AdAccountResponse payload;
payload.map(getAccountResponse);
return Response.forPayload(serializePayload(payload));
}).exceptionally(exception -> {
LOG.error("Lorem ipsum");
return checkExceptionCauses(exception);
});
}
So you see, we were returning whatever a .thenApply() returned, or an .exceptionally(). (Admittedly, I'm not well-versed in completable futures, so probably that's why I'm confused here.)
But okay, I feel that my modification does the same thing:
private CompletionStage<Response<ByteString>> getAccountById(RequestContext rc) {
return accountServiceClient.getAccount().thenApply( getAccountResponse -> {
AdAccountResponse payload;
payload.map(getAccountResponse);
// *** BEGIN CHANGES *** //
Request salesforceRequest = Request.forUri(FORCEIT_GET_BUSINESS_INFO_URI, "GET").withPayload(businessInfoRequestPayload);
return httpClient.send(salesforceRequest, rc).thenApply(salesforceResponse -> {
if (salesforceResponse.payload().isPresent()) {
// ...
} else {
// ...
}
AdAccountResponse payload;
payload.map(getAccountResponse);
return Response.forPayload(serializePayload(payload));
});
// *** END CHANGES *** //
}).exceptionally(exception -> {
LOG.error("Lorem ipsum");
return checkExceptionCauses(exception);
});
}
All I've done is add another layer of .thenApply(). But I have my inner .thenApply() return the same thing the original code was returning, and my outer .thenApply() just passes it up.
So why am I now all of a sudden getting a complaint about converting to a CompletionStage? I tried this just for kicks:
return CompletableFuture.completedFuture(checkExceptionCauses(exception));
And not surprisingly, I now got a complaint higher up about returning a CompletionStage<Response<ByteString>> instead of a Response<ByteString>.
thenApply is used if you have a synchronous mapping function.
According to the Documentation:
Returns a new CompletionStage that, when this stage completes
normally, is executed with this stage's result as the argument to the
supplied function.
On the other hand, thenCompose is used if you have an asynchronous mapping function that returns a CompletableFuture. In other words, thenCompose returns a future with the result directly, rather than a nested future.
From Documentation:
Returns a new CompletionStage that is completed with the same value as
the CompletionStage returned by the given function.
When this stage completes normally, the given function is invoked with
this stage's result as the argument, returning another
CompletionStage. When that stage completes normally, the
CompletionStage returned by this method is completed with the same
value.
So try to replace thenApply by thenCompose.