I'm looking to add lambdas to a queue to be run when the queue is polled, using the arguments passed to them when they were added to the queue. Something like below:
#FunctionalInterface
public interface Movement {
Deque<Movement> movementDeque = new ArrayDeque<>();
void move(MovementType type);
}
...
public void addToQueue(Direction direction){
MovementType type = switch (direction) {
case LEFT -> MovementType.TURN_LEFT;
case RIGHT -> MovementType.TURN_RIGHT;
case UP -> MovementType.FORWARD;
case DOWN -> MovementType.BACKWARD;
}
Movement.movementDeque.offer((m) -> subject.move(type));
}
...
Movement.movementDeque.poll(); // Running the lambda later
Is this possible? None of what I've attempted so far seems to allow me to invoke lambdas using the arguments passed to them when they were defined. Feel like I'm misunderstanding something pretty fundamental here.
I dont think its possible to store a lambda with specific paramaters (since remember, a lambda is essentially just a shorthand method), what you could do though, is change the move method to not take any arguments
public interface Movement {
void move();
}
And then you can simply queue the move method and invoke it like so
public void addToQueue(Direction direction){
MovementType type = switch (direction) {
case LEFT -> MovementType.TURN_LEFT;
case RIGHT -> MovementType.TURN_RIGHT;
case UP -> MovementType.FORWARD;
case DOWN -> MovementType.BACKWARD;
}
Movement.movementDeque.offer(() -> subject.move(type));
}
Runnable movement = movementDeque.poll();
movement.run();
Which should achieve the same result you are expecting
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()));
I love Optional in Java. It has, in one simple class, allowed me to clearly identify return types and arguments which may or may not be available.
One thing that I struggle with is the necessity of assigning it to a short-lived variable which is then inherited into every subsequent scope.
I like to use the simple variable name opt when using optionals like this:
Optional<ThingA> opt = maybeGetThing();
if (opt.isPresent()) {
ThingA usefulVariableName = opt.get();
...
But when I then need a variable name to use in this scope...
void method() {
Optional<ThingA> opt = maybeGetThing();
if (opt.isPresent()) {
ThingA usefulVariableName = opt.get();
usefulVariableName.doA();
usefulVariableName.doB();
usefulVariableName.doC();
// Duplicate local variable opt
Optional<ThingB> opt = usefulVariableName.maybeAnotherThing();
}
}
I can use things like optA and optB and so on. But I wonder if there is another way to write this code without having to enumerate my temporary variables. This just smacks of lazy variable names like a aaaa aaaaaabbb or something.
I don't want to name all of my optionals explicitly like this:
Optional<ThingA> optUsefulVariableName = maybeGetThing();
if (optUsefulVariableName.isPresent()) {
ThingA usefulVariableName = optUsefulVariableName.get();
...
While accurate, it is extremely verbose. I also try to use throwaway names like opt and i to indicate that these are in fact only temporary and should serve no purpose beyond their immediate scope (even though they will be inherited).
UPDATE:
I have seen suggestions for using ifPresent() but I don't see how I can use this for instances where I also need to perform an action if the optional is empty:
void method() {
Optional<ThingA> opt = maybeGetThing();
if (!opt.isPresent()) {
doSomethingOnlyHere();
return;
}
if (opt.isPresent()) {
ThingA usefulVariableName = opt.get();
usefulVariableName.doA();
usefulVariableName.doB();
usefulVariableName.doC();
// Duplicate local variable opt
Optional<ThingB> opt = usefulVariableName.maybeAnotherThing();
}
}
When I try to refactor with ifPresent():
void method() {
// Doesn't handle instance where I need side effects on an empty optional
maybeGetThing().ifPresent(usefulVariableName -> {
...
}
}
The most basic way to eliminate the variable and the need to call Optional#get is to use Optional.ifPresent which calls a function if the Optional has a value.
maybeGetThing().ifPresent(val -> {
// do stuff with side effects here
});
This is still quite a limited way to use Optional, as one of Optionals key purposes is to facilitate programming in a functional style. If you are a beginner this may be a little lost on you, but the idea is to have functions that return something and not functions that rely on side effects. Functions relying on side effects cannot be chained together and are generally harder to reason about.
Technically Optional is something called a Functor (from category theory). It is a wrapper around a value (Whatever T is) and it allows the value to be passed through a series of operations to operate on it and pass it to the next operation until we have what we want, then the chain of operations ends with a terminal (i.e. final) operation. The terminal operation may return the unwrapped value if it exists or it could throw or return some default value if it doesn't.
For Optional it will skip any subsequent operations if the value becomes not present.
There are common operations like map, filter, flatMap (ok that's a Monad operation) and other more java specific operations like Optional#orElse and Optional#orElseThrow.
To refactor your example code you could do this.
void method() {
return maybeGetThing().flatMap(val -> {
// eek side effects
val.doA();
val.doB();
val.doC();
return val.maybeAnotherThing();
});
}
flatMap is a way of converting an Optional of one type to an Optional of another type. If the return value weren't Optional you would use map.
You can see we have eliminated the need for names of return values in favour of naming the parameters of lambda functions. The lambda functions are scoped so you can reuse the names if that's what you want to.
I generally like to provide runnable code, so here is a contrived example of what I mean which is runnable.
import java.util.Optional;
class DummyClass {
private int val = 0;
public void doA(){ val += 1; }
public void doB(){ val += 2; }
public void doC(){ val += 3; }
public Optional<String> maybeAnotherThing(){
return Optional.of(Integer.toString(val));
}
}
public class UseOptional5 {
Optional<DummyClass> maybeGetThing(){
return Optional.of(new DummyClass());
}
String method() {
return maybeGetThing()
// you can put other operations here
.flatMap(val -> {
// eek side effects
val.doA();
val.doB();
val.doC();
return val.maybeAnotherThing();
})
// you can put other operations here too
.orElseThrow(() -> new IllegalArgumentException("fail!!"));
}
public static void main(String args[]) {
UseOptional5 x = new UseOptional5();
System.out.println(x.method());
}
}
Since Java 9 I’d do
void method() {
maybeGetThing().ifPresentOrElse(
usefulVariableName -> {
usefulVariableName.doA();
usefulVariableName.doB();
usefulVariableName.doC();
// No duplicate local variable opt
Optional<ThingB> opt = usefulVariableName.maybeAnotherThing();
},
this::doSomethingOnlyHere
);
}
My rule of thumb is you seldom need or want to use isPresent and/or get, they are low-level. For basic things ifPresent (with f) and ifPresetnOrElse are fine. Others are correct that map and flatMap are very useful too.
Using blocks of code with switch or if is a common thing when checking for events. It can be clean code when made simple, but still seems to have more lines than needed, and could be simplified using lambdas.
Block with if:
if(action == ACTION_1){
doAction1();
} else if(action == ACTION_2){
doAction2();
} else {
doDefaultAction();
}
Block with switch:
switch(action){
case ACTION_1:
doAction1();
break;
case ACTION_2:
doAction2();
break;
default:
doDefaultAction();
}
Block with lambdas using the utility class With below:
with(action)
.when(ACTION_1, this::doAction1)
.when(ACTION_2, this::doAction2)
.byDefault(this::doDefaultAction)
Using lambdas has less code, but the question is: is it easier to read than the others? Easier to maintain? Regarding performance lambdas is the worst, but for cases where performance is not important the lambdas version is shorter than the switch/if blocks.
So, how do you see it? Maybe there is a Kotlin way shorter than this, I try to focus on java only, I love Kotlin but the compilation is still too slow for my projects.
A similar utility class could be used when the block must return a specific value.
FYI, the class for the lambdas is here, I didn't check for errors, just made it quickly for this example:
public class With<T> {
private final T id;
private boolean actionFound;
private With(T id) {
this.id = id;
}
public static <T> With<T> with(T id) {
return new With<>(id);
}
public With<T> when(T expectedId, Action action) {
if (!actionFound && id == expectedId) {
actionFound = true;
action.execute();
}
return this;
}
public void byDefault(Action action) {
if (!actionFound) {
action.execute();
}
}
#FunctionalInterface
interface Action {
void execute();
}
}
As a couple has said, replacing switch with compounded methods is less efficient. Depending on your use-case, it might even be worth it to use your implementation.
Funnily enough, Oracle is actually planning to implement lambdas within switch statements, as seen in this recent JEP.
Example:
String formatted = switch (s) {
case null -> "(null)";
case "" -> "(empty)";
default -> s;
}
The switch is more flexible in that you can call functions with varying numbers of arguments, or call more than one function. You can also more easily denote when two cases lead to the same action. The fact that it's faster is just a bonus.
So in that sense I'm not sure what your With class is really adding.
However, switch has a limited number of types that it can work with. Perhaps your With class would prove to be more useful if you were to pass it predicates rather than performing simple reference equality, for example:
public With<T> when(Predicate<T> expected, Action action) {
if (!actionFound && expected.test(id)) {
actionFound = true;
action.execute();
}
return this;
}
Sample usage:
final String test = "test";
with(test)
.when(String::isEmpty, this::doAction1)
.when(s -> s.length() == 3, this::doAction2)
.byDefault(this::doDefaultAction);
replace switch with lambdas. Worth it?
No.
Because in an OO language the replacemenst for a switch or an if/else cascade is polymorphism, not "fluent API".
One option to do this is to declare static final Map<T, Action> EXPECTED_ID_TO_ACTION. Then you just can EXPECTED_ID_TO_ACTION.getOrDefault(actionId, DEFAULT_ACTION).execute(), turning ugly switch or multiple ifs into one-liner.
I couldn't find a way to do the following with Java's Optional:
if (SOME_OBJECT != null) {
doSomething(SOME_OBJECT);
} else {
doSomethingElse();
}
By using Optional, I don't mean mean replacing SOME_OBJECT == null with Optional.ofNullable(SOME_OBJECT).isPresent(), which a much longer syntax than simply checking if null.
What I would expect is something like:
Optional.ofNullable(SOME_OBJECT)
.ifPresent(this::doSomething)
.orElse(this::doSomethingElse);
I couldn't find an API like the one I just wrote. Does it exist? If so, what is it? If not, why not? :)
The second piece of code looks like an anti-pattern :( Why? Perhaps Java's architects prevented this syntax on purpose...
As mentioned in this Blog Article, Optionals will get a new method in Java 9: void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction). So, with Java, 8 you don't have something like that at the moment.
As BdoubleB97 (Bdubzz) stated, Java 9 will implement Optional#ifPresentOrElse which will take a Consumer<T> which will be applied if the Optional<T> is present, and a Runnable which will be executed if the Optional<T> is empty.
You can either update now to the Java 9 Early Access build, or you can build the method yourself with the following:
public <T> void ifPresentOrElse(Optional<T> optional, Consumer<? super T> action, Runnable emptyAction) {
if (optional.isPresent()) {
action.accept(optional.get());
} else {
emptyAction.run();
}
}
As said Java 8 does not have a construct to do exactly what you want.
I know, it's ugly, far less readable than a simple if/then/else but you can do this:
Optional.ofNullable(someObject)
.map(obj -> {
System.out.println("present");
return obj;
})
.orElseGet(() -> {
System.out.println("not present");
return null;
});
The only side effect is that you have always return something.
Or on the other hand you can handle cleanly the case isPresent().
Optional.ofNullable(someObject).ifPresent(obj -> {
System.out.println("present");
});
Java 8 presents Optional class.
Before (Java 7):
Order order = orderBean.getOrder(id);
if (order != null) {
order.setStatus(true);
pm.persist(order);
} else {
logger.warning("Order is null");
}
So on Java 8 style:
Optional<Order> optional = Optional.ofNullable(orderBean.getOrder(id));
optional.ifPresent( s -> {
s.setStatus(true);
pm.persist(s);
//Can we return from method in this place (not from lambda) ???
});
//So if return take place above, we can avoid if (!optional.isPresent) check
if (!optional.isPresent) {
logger.warning("Order is null");
}
Is it correct to use Optional in this case? Can anyone propose a more convenient way in Java 8 style?
Unfortunately, the ifPresentOrElse method you're looking for will be added only in JDK-9. Currently you can write your own static method in your project:
public static <T> void ifPresentOrElse(Optional<T> optional,
Consumer<? super T> action, Runnable emptyAction) {
if (optional.isPresent()) {
action.accept(optional.get());
} else {
emptyAction.run();
}
}
And use like this:
Optional<Order> optional = Optional.ofNullable(orderBean.getOrder(id));
ifPresentOrElse(optional, s -> {
s.setStatus(true);
pm.persist(s);
}, () -> logger.warning("Order is null"));
In Java-9 it would be easier:
optional.ifPresentOrElse(s -> {
s.setStatus(true);
pm.persist(s);
}, () -> logger.warning("Order is null"));
//Can we return from method in this plase (not from lambda) ???
Lambdas do not implement "non-local return" semantics, therefore the answer is no.
Generally, since you need side-effectful action in both the case where the value is present and not, a branching point in the code is essential—whether you wrap it in some fancy API or not. Also, FP generally helps improve referentially transparent transformations (i.e., code built around pure functions) and not side effects, so you won't find much benefit by going through the Optional API.