I have the code snippet below. But i was wondering how to try catch exception with method references. I want to write try catch block for getUserByUserId method, probably log it and catch with NotFoundException. How do i refactor this code in case of method reference userService::getUserByUserId?
List<String> listofIds= ldapUsers.stream()
.map(PersonDTO::getUserId)
.map(userService::getUserByUserId)
.filter(Optional::isPresent)
.map(Optional::get)
.map(User::get_id)
.collect(Collectors.toList());
You could write a mapper function in the class you are doing the chaining of calls:
private Optional<User> getUser(PersonDTO personDTO) {
try {
return userService.getUserByUserId(personDTO.getUserId());
} catch (Exception ex) {
log.error("Your message here", ex);
throw new NotFoundException();
}
}
And use it like this:
List<String> listofIds = ldapUsers.stream()
.map(PersonDTO::getUserId)
.map(this::getUser)
.filter(Optional::isPresent)
.map(Optional::get)
.map(User::get_id)
.collect(Collectors.toList());
Leave the stream like that add the logic you want in the getUserByUserId method. If it doesn't find a user it logs the error and throws the exception.
EDIT: since you can't modify the method, you can do the following:
List<String> listofIds= ldapUsers.stream()
.map(PersonDTO::getUserId)
.map(userId -> {
User user = userService.getUserByUserId(userId);
if(user == null) {
log.error("User not found");
throw new NotFoundException();
}
return user;
})
.filter(Optional::isPresent)
.map(Optional::get)
.map(User::get_id)
.collect(Collectors.toList());
If it's unchecked exception, you don't need to do anything. But if its checked exception then you can do something like this:
..
.map((userService) -> {
try{
...//call userService#getUserByUserId
}catch(NotFoundException e){
//log or do something else
}
}) ...
Related
I want to handle the exception without using try catch clauses.
void test() {
list.stream().map(obj -> {
Batch batch = x.findByBatchId(obj.getBatchId())
/// exception is thrown here
.orElseThrow(() -> new ResourceNotFoundException(""));
if (obj.getBatchStatus() != null) {
batchHelper.updateBatchStatus(batch, obj.getBatchStatus());
}
});
}
You can't throw checked exception that way.
You can:
Throw RuntimeException and handle it later, maybe in another method, or don't handle it at all:
public void test() {
list.stream().map(obj -> {
Batch batch = x.findByBatchId(obj.getBatchId())
/// exception is thrown here
.orElseThrow(() -> new RuntimeException(""));
if (obj.getBatchStatus() != null) {
batchHelper.updateBatchStatus(batch, obj.getBatchStatus());
}
});
Use for statement and add your exception to method signature:
public void test() throws ResourceNotFoundException {
for (BatchInfo bi: list) {
.findByBatchId(bi.getBatchId()).orElseThrow(
() -> new ResourceNotFoundException(""));
}
It also depends on what you want to do in case of exception.
If you just want to let users know they do something wrong - use RuntimeException
If you want just update Batch status, use forEach, not map :
list.stream().forEach(obj -> {
Batch batch = x.findByBatchId(obj.getBatchId())
/// exception is thrown here
.orElseThrow(() -> new RuntimeException(""));
if (obj.getBatchStatus() != null) {
batchHelper.updateBatchStatus(batch, obj.getBatchStatus());
}
});
This question already has answers here:
Java 8 Lambda function that throws exception?
(27 answers)
Closed 3 years ago.
I have some code that throws a checked exception. I want to call that code within a lambda in order to create a map from another map:
Map<String, Coordinate> map = getMap();
Map<String, Integer> result = map.entrySet().stream().collect(
toMap(x -> x.getKey(), x -> doSomething(x.getValue)));
where doSometing is the code that throws the exception:
int doSomething(Coordinate c) throws MyException { ... }
Now compiler surely complains about the exception not being handled. So I surround it with a try-catch, which looks pretty ugly:
Map<String, Integer> result = map.entrySet().stream().collect(
toMap(x -> x.getKey(), x -> {
try {
return doSomething(x.getValue());
} catch (MyException e) {
e.printStackTrace();
// return some error-code here???
}
}));
which also does not compile as we need to return something in the catch-case. However there´s not much sense in returning anything here in this exceptional case, which is why I actually do not want to handle the exception at that level. Can´t I just handle the exception in my calling code, where I create the lambda? So to say just one level above?
try {
Map<String, Integer> result = ...
} catch (MyException e) { ... }
But that does not compile because the exception thrown from the lambda is not handled.
From Baeldung's blog: you could define consumer which can throw Exception:
#FunctionalInterface
public interface ThrowingConsumer<T, E extends Exception> {
void accept(T t) throws E;
}
and a static wrapper to map checked exception to RuntimeException:
static <T> Consumer<T> throwingConsumerWrapper(
ThrowingConsumer<T, Exception> throwingConsumer) {
return i -> {
try {
throwingConsumer.accept(i);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
};
}
Then you can call it:
Map<String, Integer> result = map.entrySet().stream()
.collect(
throwingConsumerWrapper(toMap(x -> x.getKey(), x -> doSomething(x.getValue)))
);
Fist of all it's worth to filter your values. In case if you have values which can raise an exception.
Then you can use one of the popular wrappers (i.e. jooq.lambda) or write your own
map.entrySet().stream()
.filter(x -> makeSureNoExtection(x))
.collect(toMap(x -> x.getKey(), unchecked(x -> doSomething(x.getValue))));
I am trying to write a lambda function that gets employee location preference and have the code sample below.
But for my lambda function I get a compilation error at flatMap(this::buildEmployeeGeolocation)
saying Bad return type in method reference: cannot convert com.abc.EmployeeGeolocation to java.util.Optional<U>.
What am I missing here?
public Optional<EmployeeGeolocation> getEmployee(final SessionId sessionId) {
return Optional.ofNullable(employeePreferencesStore.getEmployeeAccountPreferences(sessionId))
.map(preferences -> preferences.getPreference(PreferenceKey.Location))
.filter(StringUtils::isNotBlank)
.map(this::readEmployeelocation)
.flatMap(this::buildEmployeeGeolocation);
}
private Optional<EncryptedGeolocation> readEmployeeLocation(#NonNull final String encryptedGeolocation) {
try {
return Optional.ofNullable(objectMapper.readValue(encryptedGeolocation, EmployeeGeolocation.class));
} catch (final IOException e) {
log.error("Error while reading the encrypted geolocation");
throw new RuntimeException(e);
}
}
private EmployeeGeolocation buildEmployeeGeolocation(#NonNull final EncryptedGeolocation unditheredEncryptedGeolocation) {
return EmployeeGeolocation.builder()
.latitude(10.0)
.longitude(10.0)
.accuracy(1.0)
.locationType(ADDRESS)
.build();
}
It seems like what you really need to do is swap the map and flatMap. Change the code
.map(this::readEmployeeLocation)
.flatMap(this::buildEmployeeGeolocation);
to
.flatMap(this::readEmployeeLocation) // since you already have an Optional<String>
.map(this::buildEmployeeGeolocation); // above results in Optional<EncryptedGeolocation>
Important: Inferred from the code Optional.ofNullable(...).map(...).filter(StringUtils::isNotBlank), that it would result in an Optional<String> until this operation.
Thinking of rewriting java try catch to Kotlin.
In case of an error, just need to log a status.
Is using Arrow with kotlin an overkill ?
sample implementation in Kotlin/Arrow:
fun some_method(): <SomeReturnType>{
Try.invoke {
//code which will return SomeReturnType
}.getOrElse { throwable ->
when (throwable) {
is RuntimeException -> {
// do something
}
is SomeOtherEception -> {
// do something
}
else -> {do something}
}
}
}
does anyone know, if i can invoke a method by reflection in the body of a functional interface?
I want to return a predicate. So the typical syntax would be for example
Predicate<Data> pred = data -> data.getVar1().equals("foobar");
But in my special case neither the class nor the method to call is known since it's variable.
So I wanted to get something like this:
Method method = Class.forName("Data").getMethod("getVar1", (Class[]) null);
Predicate<T> pred = data ->
((String) method.invoke(data, (Object[]) null)).equals("foobar");
But Eclipse says: "Not handled TargetInvocationException". So I surrounded it with try-catch, but Eclipse shows already the same message.
Does anyone have a clue for me?
Try this:
Predicate<T> pred = data -> {
try {
return ((String) method.invoke(data, (Object[]) null)).equals("foobar");
} catch (IllegalAccessException illegalAccessException) {
//
} catch (IllegalArgumentException illegalArgumentException) {
//
} catch (InvocationTargetException invocationTargetException) {
//
}
return false;
};