Is there a prettier way of doing the following in Java 8, avoiding isPresent and get?
void doStuff(String someValue, Optional<Boolean> doIt) {
if (doIt.isPresent()) {
if (doIt.get()) {
trueMethod(someValue);
} else {
falseMethod(someValue);
}
}
}
I tried using map, without success. But I probably didn't try hard enough?
You can use ifPresent instead of isPresent and get :
void doStuff(String someValue, Optional<Boolean> doIt) {
doIt.ifPresent (b -> {
if (b)
trueMethod(someValue);
else
falseMethod(someValue);
});
}
EDIT: fixed my code, since you can't use the ternary operator if trueMethod and falseMethod don't return anything.
This would be the functional approach using map:
Function<Boolean, Void> logic = isTrue -> {
if (isTrue) trueMethod(someValue);
else falseMethod(someValue);
return null;
};
doIt.map(logic);
However, it is really ugly, mostly because of your "not-very-functional" trueMethod/falseMethod, which both return void (leading to the ugly return null).
Related
I understand you can't return from a ifPresent() so this example does not work:
public boolean checkSomethingIfPresent() {
mightReturnAString().ifPresent((item) -> {
if (item.equals("something")) {
// Do some other stuff like use "something" in API calls
return true; // Does not compile
}
});
return false;
}
Where mightReturnAString() could return a valid string or an empty optional. What I have done that works is:
public boolean checkSomethingIsPresent() {
Optional<String> result = mightReturnAString();
if (result.isPresent()) {
String item = result.get();
if (item.equals("something") {
// Do some other stuff like use "something" in API calls
return true;
}
}
return false;
}
which is longer and does not feel much different to just checking for nulls in the first place. I feel like there must be a more succinct way using Optional.
I think all you're looking for is simply filter and check for the presence then:
return result.filter(a -> a.equals("something")).isPresent();
How about mapping to a boolean?
public boolean checkSomethingIfPresent() {
return mightReturnAString().map(item -> {
if (item.equals("something")) {
// Do some other stuff like use "something" in API calls
return true; // Does not compile
}
return false; // or null
}).orElse(false);
}
While #nullpointer and #Ravindra showed how to merge the Optional with another condition, you'll have to do a bit more to be able to call APIs and do other stuff as you asked in the question. The following looks quite readable and concise in my opinion:
private static boolean checkSomethingIfPresent() {
Optional<String> str = mightReturnAString();
if (str.filter(s -> s.equals("something")).isPresent()) {
//call APIs here using str.get()
return true;
}
return false;
}
A better design would be to chain methods:
private static void checkSomethingIfPresent() {
mightReturnFilteredString().ifPresent(s -> {
//call APIs here
});
}
private static Optional<String> mightReturnFilteredString() {
return mightReturnAString().filter(s -> s.equals("something"));
}
private static Optional<String> mightReturnAString() {
return Optional.of("something");
}
The ideal solution is “command-query separation”: Make one method (command) for doing something with the string if it is present. And another method (query) to tell you whether it was there.
However, we don’t live an ideal world, and perfect solutions are never possible. If in your situation you cannot separate command and query, my taste is for the idea already presented by shmosel: map to a boolean. As a detail I would use filter rather than the inner if statement:
public boolean checkSomethingIfPresent() {
return mightReturnAString().filter(item -> item.equals("something"))
.map(item -> {
// Do some other stuff like use "something" in API calls
return true; // (compiles)
})
.orElse(false);
}
What I don’t like about it is that the call chain has a side effect, which is not normally expected except from ifPresent and ifPresentOrElse (and orElseThrow, of course).
If we insist on using ifPresent to make the side effect clearer, that is possible:
AtomicBoolean result = new AtomicBoolean(false);
mightReturnAString().filter(item -> item.equals("something"))
.ifPresent(item -> {
// Do some other stuff like use "something" in API calls
result.set(true);
});
return result.get();
I use AtomicBoolean as a container for the result since we would not be allowed to assign to a primitive boolean from within the lambda. We don’t need its atomicity, but it doesn’t harm either.
Link: Command–query separation on Wikipedia
By the way if you really want to get value from Optional, use:
Optional<User> user = service.getCurrentUset();
return user.map(User::getId);
I am a little confused on "how to do this properly":
// return true: if present and number of lines != 0
boolean isValid(Optional<File> optFile) {
return optFile.ifPresentOrElse(f -> return !isZeroLine(f), return false);
}
private boolean isZeroLine(File f) {
return MyFileUtils.getNbLinesByFile(f) == 0;
}
I know the syntax is not correct and not compiling, but it's just for you to get the idea.
How can I turn this into 'clean code'?
i.e. avoid doing:
if (optFile.isPresent()) {//} else {//}
Dealing with boolean return type(easily inferred Predicates), one way to do that could be to use Optional.filter :
boolean isValid(Optional<File> optFile) {
return optFile.filter(this::isZeroLine).isPresent();
}
But, then using Optionals arguments seems to be a poor practice. As suggested in comments by Carlos as well, another way of implementing it could possibly be:
boolean isValid(File optFile) {
return Optional.ofNullable(optFile).map(this::isZeroLine).orElse(false);
}
On another note, ifPresentOrElse is a construct to be used while performing some actions corresponding to the presence of the Optional value something like :
optFile.ifPresentOrElse(this::doWork, this::doNothing)
where the corresponding actions could be -
private void doWork(File f){
// do some work with the file
}
private void doNothing() {
// do some other actions
}
I have a sequence of methods that I need to run sequentially, using the result of each method as a parameter in the next. However, I also check that the result of each method is "good" before calling the next method (if it's "bad" then I exit the method early. The methods return an empty Optional if they were not successful.
Is there a refactoring that I can perform to improve the code? Chain of Responsibility feels a little overboard.
private boolean isSequenceSuccessful() {
Optional<byte[]> result1 = doSomething();
if (!result1.isPresent()) {
return false;
}
Optional<byte[]> result2 = doAnotherThing(result1.get());
if (!result2.isPresent()) {
return false;
}
Optional<byte[]> result3 = doSomethingElse(result2.get());
if (!result3.isPresent()) {
return false;
}
return doMoreStuff(result3.get());
}
I don't want to use Exceptions to control the flow of the method because that's a code smell (I expect to sometimes get "bad" results).
You can write it shorter using Optional and mapping:
private boolean isSequenceSuccessful() {
return Optional.of(doSomething())
.flatMap(result1 -> doAnotherThing(result1))
.flatMap(result2 -> doSomethingElse(result2))
.map(result3 -> doMoreStuff(result3))
.orElse(false);
}
Or using method references even shorter:
private boolean isSequenceSuccessful2() {
return Optional.of(doSomething())
.flatMap(this::doAnotherThing)
.flatMap(this::doSomethingElse)
.map(this::doMoreStuff)
.orElse(false);
}
It depends what you prefer. If you want to keep the intermediate result variables use the lambda version.
Since the methods doAnotherThing and doSomethingElse do return an Optional<byte[]>, Optional.flatMap is needed to continue the mapping. Otherwise you could change the return type of these methods to return byte[] solely. Then you would use Optinal.map only, which would be more consistent.
The mapping will only be performed as long as a value is present in the Optional. If all mappings could be applied the value of the last is returned as result. Otherwise the processing will fail fast and bypass all remainig mappings to the last statement orElse and return it's value. This is false according to your code.
You could use the map method:
private boolean isSequenceSuccessful() {
Optional<byte[]> result = doSomething().map(this::doAnotherThing)
.map(this::doSomethingElse);
if (result.isPresent()) return doMoreStuff(result.get());
else return false;
}
Look at the template pattern which I sometimes refer to as the pizza pattern because it is analogous to making a pizza. (eg. createDough(), putIngredients(), bake(), package(), deliver()). This might apply to your case. There are several examples and implementations out there but pick and choose which applies best to you. In your example above, I would create an abstract class and create concrete classes/implementations. Example to give you an idea:
public abstract class SequenceChecker {
// ...
public boolean isSequenceSuccessful() {
Optional<byte[]> result1 = doSomething();
Optional<byte[]> result2 = doAnotherThing(result1);
Optional<byte[]> result3 = doSomethingElse(result2);
return doMoreStuff(result3);
}
protected abstract boolean doMoreStuff(Optional<byte[]> result);
protected abstract Optional<byte[]> doSomethingElse(Optional<byte[]> result);
protected abstract Optional<byte[]> doAnotherThing(Optional<byte[]> result);
protected abstract Optional<byte[]> doSomething();
// ...
}
Use Optional::flatMap.
private boolean isSequenceSuccessful() {
Optional<Boolean> result = doSomething()
.flatMap(this::doAnotherThing)
.flatMap(this::doSomethingElse)
.map(this::doMoreStuff);
return result.isPresent() ? result.get() : false;
}
With Java 8, I have this code:
if(element.exist()){
// Do something
}
I want to convert to lambda style,
element.ifExist(el -> {
// Do something
});
with an ifExist method like this:
public void ifExist(Consumer<Element> consumer) {
if (exist()) {
consumer.accept(this);
}
}
But now I have else cases to call:
element.ifExist(el -> {
// Do something
}).ifNotExist(el -> {
// Do something
});
I can write a similar ifNotExist, and I want they are mutually exclusive (if the exist condition is true, there is no need to check ifNotExist, because sometimes, the exist() method takes so much workload to check), but I always have to check two times. How can I avoid that?
Maybe the "exist" word make someone misunderstand my idea. You can imagine that I also need some methods:
ifVisible()
ifEmpty()
ifHasAttribute()
Many people said that this is bad idea, but:
In Java 8 we can use lambda forEach instead of a traditional for loop. In programming for and if are two basic flow controls. If we can use lambda for a for loop, why is using lambda for if bad idea?
for (Element element : list) {
element.doSomething();
}
list.forEach(Element::doSomething);
In Java 8, there's Optional with ifPresent, similar to my idea of ifExist:
Optional<Elem> element = ...
element.ifPresent(el -> System.out.println("Present " + el);
And about code maintenance and readability, what do you think if I have the following code with many repeating simple if clauses?
if (e0.exist()) {
e0.actionA();
} else {
e0.actionB();
}
if (e1.exist()) {
e0.actionC();
}
if (e2.exist()) {
e2.actionD();
}
if (e3.exist()) {
e3.actionB();
}
Compare to:
e0.ifExist(Element::actionA).ifNotExist(Element::actionB);
e1.ifExist(Element::actionC);
e2.ifExist(Element::actionD);
e3.ifExist(Element::actionB);
Which is better? And, oops, do you notice that in the traditional if clause code, there's a mistake in:
if (e1.exist()) {
e0.actionC(); // Actually e1
}
I think if we use lambda, we can avoid this mistake!
As it almost but not really matches Optional, maybe you might reconsider the logic:
Java 8 has a limited expressiveness:
Optional<Elem> element = ...
element.ifPresent(el -> System.out.println("Present " + el);
System.out.println(element.orElse(DEFAULT_ELEM));
Here the map might restrict the view on the element:
element.map(el -> el.mySpecialView()).ifPresent(System.out::println);
Java 9:
element.ifPresentOrElse(el -> System.out.println("Present " + el,
() -> System.out.println("Not present"));
In general the two branches are asymmetric.
It's called a 'fluent interface'. Simply change the return type and return this; to allow you to chain the methods:
public MyClass ifExist(Consumer<Element> consumer) {
if (exist()) {
consumer.accept(this);
}
return this;
}
public MyClass ifNotExist(Consumer<Element> consumer) {
if (!exist()) {
consumer.accept(this);
}
return this;
}
You could get a bit fancier and return an intermediate type:
interface Else<T>
{
public void otherwise(Consumer<T> consumer); // 'else' is a keyword
}
class DefaultElse<T> implements Else<T>
{
private final T item;
DefaultElse(final T item) { this.item = item; }
public void otherwise(Consumer<T> consumer)
{
consumer.accept(item);
}
}
class NoopElse<T> implements Else<T>
{
public void otherwise(Consumer<T> consumer) { }
}
public Else<MyClass> ifExist(Consumer<Element> consumer) {
if (exist()) {
consumer.accept(this);
return new NoopElse<>();
}
return new DefaultElse<>(this);
}
Sample usage:
element.ifExist(el -> {
//do something
})
.otherwise(el -> {
//do something else
});
You can use a single method that takes two consumers:
public void ifExistOrElse(Consumer<Element> ifExist, Consumer<Element> orElse) {
if (exist()) {
ifExist.accept(this);
} else {
orElse.accept(this);
}
}
Then call it with:
element.ifExistOrElse(
el -> {
// Do something
},
el -> {
// Do something else
});
The problem
(1) You seem to mix up different aspects - control flow and domain logic.
element.ifExist(() -> { ... }).otherElementMethod();
^ ^
control flow method business logic method
(2) It is unclear how methods after a control flow method (like ifExist, ifNotExist) should behave. Should they be always executed or be called only under the condition (similar to ifExist)?
(3) The name ifExist implies a terminal operation, so there is nothing to return - void. A good example is void ifPresent(Consumer) from Optional.
The solution
I would write a fully separated class that would be independent of any concrete class and any specific condition.
The interface is simple, and consists of two contextless control flow methods - ifTrue and ifFalse.
There can be a few ways to create a Condition object. I wrote a static factory method for your instance (e.g. element) and condition (e.g. Element::exist).
public class Condition<E> {
private final Predicate<E> condition;
private final E operand;
private Boolean result;
private Condition(E operand, Predicate<E> condition) {
this.condition = condition;
this.operand = operand;
}
public static <E> Condition<E> of(E element, Predicate<E> condition) {
return new Condition<>(element, condition);
}
public Condition<E> ifTrue(Consumer<E> consumer) {
if (result == null)
result = condition.test(operand);
if (result)
consumer.accept(operand);
return this;
}
public Condition<E> ifFalse(Consumer<E> consumer) {
if (result == null)
result = condition.test(operand);
if (!result)
consumer.accept(operand);
return this;
}
public E getOperand() {
return operand;
}
}
Moreover, we can integrate Condition into Element:
class Element {
...
public Condition<Element> formCondition(Predicate<Element> condition) {
return Condition.of(this, condition);
}
}
The pattern I am promoting is:
work with an Element;
obtain a Condition;
control the flow by the Condition;
switch back to the Element;
continue working with the Element.
The result
Obtaining a Condition by Condition.of:
Element element = new Element();
Condition.of(element, Element::exist)
.ifTrue(e -> { ... })
.ifFalse(e -> { ... })
.getOperand()
.otherElementMethod();
Obtaining a Condition by Element#formCondition:
Element element = new Element();
element.formCondition(Element::exist)
.ifTrue(e -> { ... })
.ifFalse(e -> { ... })
.getOperand()
.otherElementMethod();
Update 1:
For other test methods, the idea remains the same.
Element element = new Element();
element.formCondition(Element::isVisible);
element.formCondition(Element::isEmpty);
element.formCondition(e -> e.hasAttribute(ATTRIBUTE));
Update 2:
It is a good reason to rethink the code design. Neither of 2 snippets is great.
Imagine you need actionC within e0.exist(). How would the method reference Element::actionA be changed?
It would be turned back into a lambda:
e0.ifExist(e -> { e.actionA(); e.actionC(); });
unless you wrap actionA and actionC in a single method (which sounds awful):
e0.ifExist(Element::actionAAndC);
The lambda now is even less 'readable' then the if was.
e0.ifExist(e -> {
e0.actionA();
e0.actionC();
});
But how much effort would we make to do that? And how much effort will we put into maintaining it all?
if(e0.exist()) {
e0.actionA();
e0.actionC();
}
If you are performing a simple check on an object and then executing some statements based on the condition then one approach would be to have a Map with a Predicate as key and desired expression as value
for example.
Map<Predicate<Integer>,Supplier<String>> ruleMap = new LinkedHashMap <Predicate<Integer>,Supplier<String>>(){{
put((i)-> i<10,()->"Less than 10!");
put((i)-> i<100,()->"Less than 100!");
put((i)-> i<1000,()->"Less than 1000!");
}};
We could later stream the following Map to get the value when the Predicate returns true which could replace all the if/else code
ruleMap.keySet()
.stream()
.filter((keyCondition)->keyCondition.test(numItems,version))
.findFirst()
.ifPresent((e)-> System.out.print(ruleMap.get(e).get()));
Since we are using findFirst() it is equivalent to if/else if /else if ......
I have the following code:
void f(String t)
{
if(t.equals("a"))
{
someObject.setType(ObjectType.TYPE_A);
}
else if(t.equals("b"))
{
someObject.setType(ObjectType.TYPE_B);
}
// 50 more similar code
}
Is there any simple way to rewrite the if-else condition so as not to have that much code?
You should use something to eliminate the repetition of someObject.setType(ObjectType....)) If ObjectType is an enum, then write a method there similar to valueOf that will achieve that. See if you like this kind of solution:
void f(String t) { someObject.setType(ObjectType.byName(t)); }
enum ObjectType {
TYPE_A, TYPE_B;
public static ObjectType byName(String name) {
return valueOf("TYPE_" + name.toUpperCase());
}
}
Use a Map (which you'll have to populate) that maps from String to whatever type your ObjectType.TYPE_x values are.
I would add this as a functionality of the enum:
public enum ObjectType {
TYPE_A("a"),
TYPE_B("b");
private String stringType;
private ObjectType(String stringType) {
this.stringType = stringType;
}
public String getStringType() {
return this.stringType;
}
public static ObjectType fromStringType(String s) {
for (ObjectType type : ObjectType.values()) {
if (type.stringType.equals(s)) {
return type;
}
}
throw new IllegalArgumentException("No ObjectType with stringType " + s);
}
}
...
void f(String t) {
someObject.setType(ObjectType.fromStringType(t));
}
If you can refactor t into a char, you could use switch instead (Java 6):
void f(char t) {
switch(t) {
case 'a`:
someObject.setType(ObjectType.TYPE_A);
break;
case 'b':
someObject.setType(ObjectType.TYPE_B);
break;
// ...
}
}
As Marko pointed out, you could go with String too in Java 7.
It isn't that much shorter, but more elegant. Moreover, I think it might be faster too, as switch works close to O(1) with jump tables (Can somebody confirm whether this is true?), whether a number of if statements is O(n).
Fore more complex implementations than just a single setType you might think of a State Pattern implementation too.
1.You can go for Switch statement if you have number of if conditions more than 3.
2.you can convert your if else statements to ternary operations
The other suggestions are great - particularly smarter enums and maps. But the first most basic refactoring I would tackle here is to extract a method to return the enum directly and have the caller perform nothing more than the setType to that method's return value.
void f(String t) {
final ObjectType type = findType(t);
if (type != null)
someObject.setType(type);
}
ObjectType findType(String t) {
if (t.equals("a")) return ObjectType.TYPE_A;
if (t.equals("b")) return ObjectType.TYPE_B;
// 50 more similar code
}
In some cases this will be sufficient in and of itself; in others the findType() method may lead you to a simple map- or enum-based solution.