Have a function like this:
public void toDo(Req req){
if(req.getSection().equals("A")) {
return execA(req);
}
if(req.getSection().equals("B")) {
return execB(req);
}
if(req.getSection().equals("N")) {
return execN(req);
}
}
How can I simplify it? The general idea, how to exclude if statements for the identification type of function - Strings - A, B, N. Any solutions with Java 8 like pattern matching with Scala?
Can't you use just a simple switch?
switch (req.getSection()){
case "A" : execA(req); break;
case "B" : execB(req); break;
case "N" : execN(req); break;
default: break;
}
Besides the switch solution, which works for strings and int values, you can use a Map:
Map<String,Consumer<Req>> handlers;
{
handlers.put("A", req -> execA(req));
handlers.put("B", req -> execB(req));
handlers.put("N", req -> execN(req));
}
Consumer<Req> defaultBehavior=req-> {
throw new IllegalArgumentException(req.getSection());
};
public void toDo(Req req) {
handlers.getOrDefault(req.getSection(), defaultBehavior).accept(req);
}
Besides supporting other key types, it allows to assemble the map at runtime, e.g. using handlers provided by different, perhaps dynamically loaded, modules, etc.
Using reflection and the array of methods you have on your class, you could apply a filter (if-replacement), mapping (to return value) and optionally defining a default value (orElse).
This approach might be good, if either the number of cases gets huge or dynamic. But for your particular case, I think it's overkill. Better stick to the switch-case solution.
public Optional<Object> toDo(Req req) {
return Stream.of(this.getClass().getMethods())
.filter(m -> m.getName().equals("exec" + req.getSection()))
.map(this::invokeUnchecked).findFirst();
}
private Object invokeUnchecked(final Method m) {
try {
return m.invoke(this);
} catch (IllegalAccessException| InvocationTargetException e) {
throw new RuntimeException(e);
}
}
In case you don't want to use an optional, you have to declare a default with .findFirst().orElse(() -> ...)
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()));
Let's suppose we have an if statement like this:
public A save(A a) {
if (isValid.test(a)) {
return aRepository.save(a);
}
throw new ANotValidException("A is not valid");
}
isValid is a Predicate and it may look like:
private Predicate<A> isValid = (a) -> (a != null);
What do you think? Can I make it cleaner somehow?
I mean, for example using an Optional to reduce it in 1 line with an .orElseThrow();
A more precise version using Optional and throwing a custom Exception shall be :
public A save(A a) throws ANotValidException { // throws the custom exception
return Optional.ofNullable(a) // since your predicate is to check for not null
.map(aRepository::save)
.orElseThrow(() -> new ANotValidException(a + "A is not valid"));
}
An Optional can make the code more readable, particularly around the use of your predicate object:
public A save(A a) {
return Optional.ofNullable(a)
.filter(isValid)
.map(aRepository::save)
.orElseThrow(() -> new ANotValidException("A is not valid"));
}
You can also get rid of the predicate altogether as it's simple enough to use Objects::nonNull (unless your real predicate's test is more complex). And in that case, keeping your current condition checks would probably make more sense (in my opinion).
One could argue that it would be more natural to read it in the opposite order, that is first handle the validation and the result of it and then move on to saving the object.
public A save(A a) {
if (!isValid.test(a)) {
throw new ANotValidException("A is not valid");
}
return aRepository.save(a);
}
I can't figure out how to factor out this code.
private CompletionStage<Response<String>> foo(RequestContext rc) {
final Optional<String> campaignIdOpt = rc.request().parameter("campaignId").filter(s -> !s.isEmpty());
final Optional<String> creativeIdOpt = rc.request().parameter("creativeId").filter(s -> !s.isEmpty());
Optional<Uuid> campaignIdOptOfUuid = Optional.empty();
if (campaignIdOpt.isPresent()) {
try {
campaignIdOptOfUuid = Optional.of(UuidUtils.fromString(campaignIdOpt.get()));
} catch (IllegalArgumentException e) {
LOG.error(String.format("Invalid campaignId: %s", campaignIdOpt.get()), e);
return CompletableFuture.completedFuture(
Response.forStatus(Status.BAD_REQUEST.withReasonPhrase("Invalid campaignId provided.")));
}
}
Optional<Uuid> creativeIdOptOfUuid = Optional.empty();
if (creativeIdOpt.isPresent()) {
try {
creativeIdOptOfUuid = Optional.of(UuidUtils.fromString(creativeIdOpt.get()));
} catch (IllegalArgumentException e) {
LOG.error(String.format("Invalid creativeId: %s", creativeIdOpt.get()), e);
return CompletableFuture.completedFuture(
Response.forStatus(Status.BAD_REQUEST.withReasonPhrase("Invalid creativeId provided.")));
}
}
// Simplified, do something with Uuids.
return bar(campaignIdOptOfUuid, creativeIdOptOfUuid);
}
Basically, we very frequently need to parse Google protobuf Uuids from a query string to pass on to another service that will find (or not find). We need to pass along an empty optional if a parameter was not set or an empty string, as both cases mean, "Don't filter by this parameter." Finally, if the string doesn't parse at all, then we want to immediately return an error 400 (Bad Request), rather than pass along a non-sense param to the service.
So, codewise, I want a utility method that
takes an Optional<String>, and
returns an Optional<Uuid> if present, Optional.empty() otherwise, and
if an exception is thrown, return an error from the original context.
But obviously, I can't "double-return." What pattern do I use to achieve this though? I tried to create an encapsulator for both an Optional<Uuid> and a CompletionStage<Response<String>> but it was awkward. Is there some idiomatic way of doing this?
You can use a loop. A loop allows you to handle all elements equally, thus removing the code duplication, while still allowing to return immediately:
private CompletionStage<Response<String>> foo(RequestContext rc) {
String[] parameters = {"campaignId", "creativeId" };
List<Optional<Uuid>> uuids = new ArrayList<>(parameters.length);
for(String param: parameters) {
Optional<String> o1 = rc.request().parameter(param).filter(s -> !s.isEmpty());
Optional<Uuid> o2;
try {
o2 = o1.map(UuidUtils::fromString);
} catch(IllegalArgumentException e) {
LOG.error(String.format("Invalid %s: %s", param, o1.get()), e);
return CompletableFuture.completedFuture(
Response.forStatus(Status.BAD_REQUEST
.withReasonPhrase("Invalid "+param+ " provided.")));
}
uuids.add(o2);
}
// Simplified, do something with Uuids.
return bar(uuids.get(0), uuids.get(1));
}
Otherwise, you would need to create a method returning an object holding two alternative results (like Either); the JDK does not provide such a type yet. A method could simply throw on an erroneous condition but that would bring you back to square one when the common code is mostly the exception handling.
Note that calling Optional.map on an empty optional will already return an empty optional, without evaluating the provided function, so you don’t need to check via ifPresent, etc.
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 am looking for what is the recommended practice in rxjava2 to handle a case where one flowable leads to conditional behaviors.
More concretely, I have a Maybe<String> for which I want to Update the String on the database if the String exists or, if it doesn't exists I want to create a new String and save it on the database.
I thought of the below but obviously it is not what I am looking for:
Maybe<String> source = Maybe.just(new String("foo")); //oversimplified source
source.switchIfEmpty(Maybe.just(new String("bar"))).subscribe(result ->
System.out.println("save to database "+result));
source.subscribe(result -> System.out.println("update result "+result));
The above obviously produces
save to database foo
update result foo
I tried also the below which gives the expected result but still feel it's... weird.
Maybe<String> source = Maybe.just(new String("foo")); //oversimplified source
source.switchIfEmpty(Maybe.just(new String("bar")).doOnSuccess(result ->
System.out.println("save to database "+result))).subscribe();
source.doOnSuccess(result -> System.out.println("update result "+result)).subscribe();
How can I have an action for when the result exists and when it doesn't exists? How is that use case supposed to be handled in rxjava2?
Update 01
I tried the below and it looks cleaner than what I came up with above. Note sure it is recommended rxjava2 practice however...
Maybe.just(new String("foo"))
.map(value -> Optional.of(value))
.defaultIfEmpty(Optional.empty())
.subscribe(result -> {
if(result.isPresent()) {
System.out.println("update result "+result);
}
else {
System.out.println("save to database "+"bar");
}
});
You have the isEmpty() operator that will return you Boolean if the Maybe source is empty or not, and then you can flatMap it and write a if else statement depending on that Boolean
This is a common pattern in our code as well, though in our case the choices are themselves async. You can't get quite the right semantic by simply composing flatMapX and switchIfEmpty (in either order), so I am curious why this isn't part of the API.
Here's what we're doing for now (this example for when the 2 options are both Completables, we have similar things for the other types as well):
public static <T> Completable flatMapCompletable(Maybe<T> target,
#ClosureParams(FirstParam.FirstGenericType.class)
Closure<? extends CompletableSource> completableSupplier,
Supplier<CompletableSource> emptySupplier) {
Maybe<T> result = target.cache();
return result.isEmpty().flatMapCompletable(empty -> {
if (empty) {
return emptySupplier.get();
} else {
return result.flatMapCompletable(completableSupplier::call);
}
});
}
We're using Groovy, so we package these up as extension methods. I'm not thrilled with the need to use cache() so I'm wondering if there is a better alternative. From looking at the code, an operator which basically combines flatMapX and switch looks like it wouldn't be too hard (but I feel like I'm missing something).
Try something like this. checkDB can return a Maybe or Single or whatever which emits either an optional or a wrapper Object.
checkDB(String)
.flatMap(s -> {
if (s.isPresent()) {
return updateDB(s.get());
} else {
return insertDB("new String");
}
})
There is an solution using the flatMap call with 3 params
fun addOrUpdate(message: LocalMessage): Single<LocalMessage> {
return getById(message.id) // returns Maybe
.flatMap(
Function {
update(message) // onSuccess update call returns Single
},
Function {
Single.error(it) // onError
},
Callable {
add(message) // onComplete add call returns Single
}
)
}
}
Or shorter version
fun addOrUpdate(message: LocalMessage): Single<LocalMessage> {
return getById(message.id) // returns Maybe
.flatMap(
{
update(message) // onSuccess update call returns Single
},
{
Single.error(it) // onError
},
{
add(message) // onComplete add call returns Single
}
)
}
}