I have this switch statement that has the exact same function code repeated twice and I would like to DRY it up:
case "form" -> handleProvider.withHandle(handle -> handle.attach(FormDao.class).findFormById(id))
.thenApply(form -> { // Form.class
if (form == null) throw exceptionIfNotFound;
return form;
})
.thenApply(obj -> obj.exportedDocument);
case "note" -> handleProvider.withHandle(handle -> handle.attach(NoteDao.class).findNoteById(id))
.thenApply(note -> { // Note.class
if (note == null) throw exceptionIfNotFound;
return note;
})
If IntelliJ extract the common bits I get
final Function<Form,Form> formFormFunction = form -> {
if (form == null) throw exceptionIfNotFound;
return form;
};
which obviously just works for one code path; the Form objects, but not the Note objects. The two objects do not actually implement the same interface here, but on the other hand, I do not make use of any specific interface in the code. I just want to say I have a method that takes a and outputs a unchanged, and that T could be anything.
Make this into a method rather than a variable. This way you can make it generic.
private static <T> Function<T, T> getNullCheckFunction() {
return t -> {
if (form == null) throw exceptionIfNotFound;
return t;
};
}
Then you can do:
case "form" -> handleProvider.withHandle(handle -> handle.attach(FormDao.class).findFormById(id))
.thenApply(getNullCheckFunction()) // here!
.thenApply(obj -> obj.exportedDocument);
case "note" -> handleProvider.withHandle(handle -> handle.attach(NoteDao.class).findNoteById(id))
.thenApply(getNullCheckFunction()) // here!
Note that what you are doing in the function returned by getNullCheckFunction is very similar to Objects.requireNonNull. If you are fine with throwing NullPointerException instead of your own exception, you can just do:
.thenApply(Objects::requireNonNull)
Related
I can't figure it out, how to do this method without the if/else:
public Mono<Token> doAuthorization(InputDto dto) {
if (isXStepNeeded(dto)) {
return doXStep(dto)
.then(doYStep(dto.getRfid()));
} else {
return doYStep(dto.getRfid());
}
}
private boolean isXStepNeeded(InputDto dto) {
//simple non blocking check on the dto
}
private Mono<OtherDto> doXStep(InputDto dto) {
//checking something and returning Mono.error() if it fails
}
private Mono<Token> doYStep(String tokenUid) {
//...
}
As you can see, the X and Y steps are independent of each other. Is there a nice, readable way of writing doAuthorization that does not use if/else and I only have to write down doYStep() once?
There is no way to do this without an if else while keeping it readable. Some options to do while keeping it readable include using "ternary operator" and new "switch case" introduced in Java 14.
Reduce it to one line using ternary operator:
return isXStepNeeded(dto) ? doXStep(dto).then(doYStep(dto.getRfid())) : doYStep(dto.getRfid());
Or use the new switch case:
return switch (Boolean.toString(isXStepNeeded(dto))) {
case "true" -> doXStep(dto).then(doYStep(dto.getRfid()));
default -> doYStep(dto.getRfid());
};
EDIT:
Since you don't want to write doYStep twice, you can do:
return Mono.just(isXStepNeeded(dto))
.filter(b -> b)
.flatMap(b -> doXStep(dto))
.then(doYStep(dto.getRfid()));
How can I handle null checks in the below code using Java 8 when my counterparty can be null.
I want to set counterParty only if it has a value and not set if it is empty.
public static Iterable<? extends Trade> buildTrade (final List<Trade> trade) {
return () -> trade.stream()
.map(trade -> Trade.newBuilder()
.setType(trade.type())
.setUnit(trade.unit())
.setCounterParty(trade.counterParty())
.build())
.iterator();
}
You can use the following code:
trade.stream()
.map(trade -> {
TradeBuilder tb = Trade.newBuilder()
.setType(trade.type())
.setUnit(trade.unit());
Optional.ofNullable(trade.counterParty())
.ifPresent(tb::setCounterParty);
return tb.build();
})
.iterator();
Or without Optional:
trade.stream()
.map(trade -> {
TradeBuilder tb = Trade.newBuilder()
.setType(trade.type())
.setUnit(trade.unit());
if(trade.counterParty() != null) tb.setCounterParty(trade.counterParty());
return tb.build();
})
.iterator();
The stream aspect of this has no relevance to the question; let's strip it out:
trade -> Trade.newBuilder()
.setType(trade.type())
.setUnit(trade.unit())
.setCounterParty(trade.counterParty())
.build()
You're asking to not set counterParty if it is null.
A really easy way to do this would be to modify builder class's setCounterParty() to do nothing and return, if the parameter is null.
TradeBuilder setCounterParty(CounterParty cp) {
if(cp != null) {
this.counterParty = cp;
}
return this;
}
You do need to ensure that this behaviour is consistent with other callers' needs.
If your builder is being dynamically generated by some framework (Lombok etc), you might not have code in which you can easily make this change -- but most such frameworks have mechanisms that allow you to take control of that kind of thing.
If you can't modify the builder, you can break up the calls to it, and surround
one call with an if:
trade -> {
TradeBuilder b = Trade.newBuilder()
.setType(trade.type())
.setUnit(trade.unit());
if(trade.counterParty() != null) {
b.setCounterParty(trade.counterParty());
}
return b.build()
}
I often have a problem with Optional and similar classes Option, Try, Either from VAVR for example.
Let's say I have some Optional, and if it's empty I want to immediately return from a method (without exception, since my method is returning Optional aswell, so getOrElseThrow is out of the picture) and if it's present I want to further process it.
public Optional<Integer> converter() {
Optional<String> opt = getSomething();
if(!opt.isPresent())
return Optional.empty();
String value = opt.get();
// some manipulations on value, such as map and flatMap would cause a huge mess
return Integer.parseInt(value);
}
I just need to return immediately in case value is empty, I can't do chain of map and flatMap. The whole pain is doing .get(). Something like getOrElseThrow, but with return instead of throw would be fantastic - getOrElseReturn. Obviously not possible in Java, so I thought about trying this in Kotlin.
fun safeOptional(): Optional<Int> {
val extracted = Optional.of("123")
.getOrElseReturn { return Optional.empty() }
val modified = extracted.toInt() * 2
return Optional.of(modified)
}
private inline fun <T> Optional<T>.getOrElseReturn(block: (Optional<T>) -> T): T {
return if (!this.isPresent)
block(this)
else
this.get()
}
Much to my surprise it actually does what I want. If I change the Optional.of("123") to Optional.empty() it immediately returns from a method. I don't understand how it compiles though.
My method needs a block: (Optional<T>) -> T, otherwise it wouldn't compile. So in my case I have Optional<String> and I need to pass a block: (Optional<String>) -> String, but hey - the block that I have is nowhere close to this and it still compiles, how?
When I extract the block to variable it becomes val block: (Optional<String>) -> Nothing (I guess return statement is Nothing) and it still compiles, surprising me even more.
btw I know this code is not strictly what I want - someone can pass another block without non-local return to the method, but I don't think there is another way
Extract the second part of your method into another private method and call getSomething().map(this::otherPrivateMethod)
It will not be invoked if no value is present in getSomething()
Basically,
public Optional<Integer> converter() {
return getSomething().map(this::privateConverter);
}
private Integer privateConverter(Integer integer) {
// some manipulations on value, such as map and flatMap would cause a huge mess
return Integer.parseInt(value);
}
Answering the Kotlin part:
fun safeOptional(): Optional<Int> {
val extracted = Optional.of("123")
.getOrElseReturn { return Optional.empty() }
.......
}
The return here is not return from a lambda, but rather a return from function safeOptional so therefore lambda doesn't return anything (it returns Nothing). Lambda returning Nothing can be passed as lambda returning anything.
To get a compile error, you should return from lambda instead:
val extracted = Optional.of("123")
.getOrElseReturn { return#getOrElseReturn Optional.empty() }
Generally, Optional are not needed in Kotlin. You should use nullable types instead. You would combine them with nullsafe operators (e.g. the Elvis operator -- ?::
fun nullsafe(x: String?): Optional<Int> {
val extracted = x ?: return Optional.empty()
val modified = extracted.toInt() * 2
return Optional.of(modified)
}
nullsafe("2") // => Optional[4]
nullsafe(null) // => Optional.empty
I have an Try<Option<Foo>>. I want to flatMap Foo into a Bar, using it using an operation that can fail. It's not a failure if my Option<Foo> is an Option.none(), (and the Try was a success) and in this case there's nothing to do.
So I have code like this, which does work:
Try<Option<Bar>> myFlatMappingFunc(Option<Foo> fooOpt) {
return fooOpt.map(foo -> mappingFunc(foo).map(Option::of) /* ew */)
.getOrElse(Try.success(Option.none()); // double ew
}
Try<Bar> mappingFunc(Foo foo) throws IOException {
// do some mapping schtuff
// Note that I can never return null, and a failure here is a legitimate problem.
// FWIW it's Jackson's readValue(String, Class<?>)
}
I then call it like:
fooOptionTry.flatMap(this::myFlatMappingFunc);
This does work, but it looks really ugly.
Is there a better way to flip the Try and Option around?
Note 1: I actively do not want to call Option.get() and catch that within the Try as it's not semantically correct. I suppose I could recover the NoSuchElementException but that seems even worse, code-wise.
Note 2 (to explain the title): Naively, the obvious thing to do is:
Option<Try<Bar>> myFlatMappingFunc(Option<Foo> fooOpt) {
return fooOpt.map(foo -> mappingFunc(foo));
}
except this has the wrong signature and doesn't let me map with the previous operation that could have failed and also returned a successful lack of value.
When you are working with monads, each monad type combine only with monads of same type. This is usually a problem because the code will come very unreadable.
In the Scala world, there are some solutions, like the OptionT or EitherT transformers, but do this kind of abstractions in Java could be difficult.
The simple solution is to use only one monad type.
For this case, I can think in two alternatives:
transform fooOpt to Try<Foo> using .toTry()
transform both to Either using .toEither()
Functional programmers are usually more comfortable with Either because exceptions will have weird behaviors, instead Either usually not, and both works when you just want to know why and where something failed.
Your example using Either will look like this:
Either<String, Bar> myFlatMappingFunc(Option<Foo> fooOpt) {
Either<String, Foo> fooE = fooOpt.toEither("Foo not found.");
return fooE.flatMap(foo -> mappingFunc(foo));
}
// Look mom!, not "throws IOException" or any unexpected thing!
Either<String, Bar> mappingFunc(Foo foo) {
return Try.of(() -> /*do something dangerous with Foo and return Bar*/)
.toEither().mapLeft(Throwable::getLocalizedMessage);
}
I believe this is simply a sequence function (https://static.javadoc.io/io.vavr/vavr/0.9.2/io/vavr/control/Try.html#sequence-java.lang.Iterable-) that you are looking for:
Try.sequence(optionalTry)
You can combine Try.sequence and headOption functions and create a new transform function with a little better look, in my opinion, also you can use generic types to get a more reusable function :) :
private static <T> Try<Option<T>> transform(Option<Try<T>> optT) {
return Try.sequence(optT.toArray()).map(Traversable::headOption);
}
If I understand correctly, you want to :
keep the first failure if happens
swap the second when mapping to json for an empty option.
Isn t it simpler if you decompose your function in such a way:
public void keepOriginalFailureAndSwapSecondOneToEmpty() {
Try<Option<Foo>> tryOptFoo = null;
Try<Option<Bar>> tryOptBar = tryOptFoo
.flatMap(optFoo ->
tryOptionBar(optFoo)
);
}
private Try<Option<Bar>> tryOptionBar(Option<Foo> optFoo) {
return Try.of(() -> optFoo
.map(foo -> toBar(foo)))
.orElse(success(none())
);
}
Bar toBar(Foo foo) throws RuntimeException {
return null;
}
static class Bar {
}
static class Foo {
}
The solution of throughnothing and durron597 helped me there. This is my groovy test case:
def "checkSomeTry"() {
given:
def ex = new RuntimeException("failure")
Option<Try<String>> test1 = Option.none()
Option<Try<String>> test2 = Option.some(Try.success("success"))
Option<Try<String>> test3 = Option.some(Try.failure(ex))
when:
def actual1 = Try.sequence(test1).map({ t -> t.toOption() })
def actual2 = Try.sequence(test2).map({ t -> t.toOption() })
def actual3 = Try.sequence(test3).map({ t -> t.toOption() })
then:
actual1 == Try.success(Option.none())
actual2 == Try.success(Option.some("success"))
actual3 == Try.failure(ex)
}
I have an assignment in which I need to convert the following pre-Java 8 code to Java 8 code. Below is just one method which is giving me hard time to finish up:
public static List<VehicleMake> loadMatching(Region region, String nameStartsWith, VehicleLoader loader) {
if ((nameStartsWith == null) || (region == null) || (loader == null)) {
throw new IllegalArgumentException("The VehicleLoader and both region and nameStartsWith are required when loading VehicleMake matches");
}
List<VehicleMake> regionMakes = loader.getVehicleMakesByRegion(region.name());
if (regionMakes == null) {
return null;
}
List<VehicleMake> matches = new ArrayList<>(regionMakes.size());
for (VehicleMake make : regionMakes) {
if ((make.getName() == null) || !make.getName().startsWith(nameStartsWith)) {
continue;
}
matches.add(make);
}
return matches;
}
I want to remove the null checks by using Optional<T> without modifying previously created classes and interfaces.
I tried to begin by changing the method return type and doing the following but compiler is throwing this error:
Bad return type in method reference since the VehicleMake class doesn't have optional instance fields.
Following is my code attempt:
public static Optional<List<VehicleMake>> loadMatchingJava8(Region region, String nameStartsWith, VehicleLoader loader) {
Optional<List<VehicleMake>> regionMakes = Optional.ofNullable(loader).ifPresent(loader.getVehicleMakesByRegion(Optional.ofNullable(region).ifPresent(region.name())));
/*
TODO rest of the conversion
*/
}
EDIT: Removed the flatMap and corrected code by not passing argument to method reference. But now it is not letting me pass region.name() to getVehicleMakesByRegion()
EDIT: Pass in consumer to ifPresent():
Optional<List<VehicleMake>> regionMakes = Optional.ofNullable(loader).ifPresent(()-> loader.getVehicleMakesByRegion(Optional.ofNullable(region).ifPresent(()->region.name()));
You may replace your initial null checks with
Optional.ofNullable(nameStartsWith)
.flatMap(x -> Optional.ofNullable(region))
.flatMap(x -> Optional.ofNullable(loader))
.orElseThrow(() -> new IllegalArgumentException(
"The VehicleLoader and both region and nameStartsWith"
+ " are required when loading VehicleMake matches"));
but it’s an abuse of that API. Even worse, it wastes resource for the questionable goal of providing a rather meaningless exception in the error case.
Compare with
Objects.requireNonNull(region, "region is null");
Objects.requireNonNull(nameStartsWith, "nameStartsWith is null");
Objects.requireNonNull(loader, "loader is null");
which is concise and will throw an exception with a precise message in the error case. It will be a NullPointerException rather than an IllegalArgumentException, but even that’s a change that will lead to a more precise description of the actual problem.
Regarding the rest of the method, I strongly advice to never let Collections be null in the first place. Then, you don’t have to test the result of getVehicleMakesByRegion for null and won’t return null by yourself.
However, if you have to stay with the original logic, you may achieve it using
return Optional.ofNullable(loader.getVehicleMakesByRegion(region.name()))
.map(regionMakes -> regionMakes.stream()
.filter(make -> Optional.ofNullable(make.getName())
.filter(name->name.startsWith(nameStartsWith))
.isPresent())
.collect(Collectors.toList()))
.orElse(null);
The initial code, which is intended to reject null references, should not get mixed with the actual operation which is intended to handle null references.
I have updated your code with Optional:
public static List<VehicleMake> loadMatchingJava8(Region region, String nameStartsWith, VehicleLoader loader) {
Optional<List<VehicleMake>> regionMakes = Optional.ofNullable(region)
.flatMap(r -> Optional.ofNullable(loader).map(l -> l.getVehicleMakesByRegion(r.name())));
return Optional.ofNullable(nameStartsWith)
.map(s -> regionMakes
.map(Collection::stream)
.orElse(Stream.empty())
.filter(make -> make.getName() != null && make.getName().startsWith(s))
.collect(Collectors.toList()))
.orElse(Collections.emptyList());
}
If you really want to convert flow control to Optional, the code keep consistent with yours should be like this(I break the code in 2 lines for printing):
public static Optional<List<VehicleMake>> loadMatchingJava8(Region region,
String nameStartsWith,
VehicleLoader loader) {
if ((nameStartsWith == null) || (region == null) || (loader == null)) {
throw new IllegalArgumentException("The VehicleLoader and both region and " +
"nameStartsWith are required when loading VehicleMake matches");
}
return Optional.ofNullable(loader.getVehicleMakesByRegion(region.name()))
.map(makers -> makers.stream()
.filter((it) -> it.getName() != null
&& it.getName().startsWith(nameStartsWith))
.collect(Collectors.toList()));
}
NOTE: you can see more about why do not abuse Optional in this question.
I can't say this is very elegant, but it should satisfy your requirement. There are no explicit null checks, but it'll throw the exception if any input parameters are null, and it filters out vehicles with invalid names from the resulting list.
public static List<VehicleMake> loadMatching(Region region, String nameStartsWith, VehicleLoader loader) {
return Optional.ofNullable(nameStartsWith)
.flatMap(startWith -> Optional.ofNullable(loader)
.flatMap(vl -> Optional.ofNullable(region)
.map(Region::name)
.map(vl::getVehicleMakesByRegion))
.map(makes -> makes.stream()
.filter(make -> Optional.ofNullable(make.getName())
.filter(name -> name.startsWith(startWith))
.isPresent())
.collect(Collectors.toList())))
.orElseThrow(() -> new IllegalArgumentException("The VehicleLoader and both region and nameStartsWith are required when loading VehicleMake matches"));