Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
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
–
–
–
(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 ......
–
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.