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!

Out of curiosity, just what benefit are you hoping to gain by replacing if-else statements with lambdas? (The only side effects I can think of are extra overhead for the code execution, and just being a saddest to the poor sap who has to maintain this pattern later) – Tezra Apr 16, 2018 at 13:23 Just FYI, if I saw you doing this in production code, I'd go have a discussion with our supervisor/manager about your inability to write clean, simple code. Use the if/else in production. – jpmc26 Apr 16, 2018 at 21:47 @Michael Sorry if I've lost all patience with people writing bad code because they were trying to follow some principle or fad. Been trying to get a system like that on the rails for about 6 years, with a few months off where someone drove it way further off the rails while I was gone. (No joke, we've had to rewrite nearly everything that was done during that period, the parts that have actually made it to prod, anyway.) So I try to dissuade thinking that's not problem solving based whenever I can, to save as many as possible the heartache. – jpmc26 Apr 16, 2018 at 23:13 To echo what some others have said: it’s fine if you’re doing this for practice, but please don’t ever do this in real code. Developers, yourself included, spend a lot more time maintaining existing code than writing new stuff, so it is in your best interest, and ours, to write your code so it is as easy to read as possible. if/else statements are normal and good. – VGR Apr 17, 2018 at 0:57

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.

@Andrew I did not expect 4 upvotes, as I just wanted to indicate that a custom exists probably points to something that Optional would be more suited for. And forEach definitely is wrong, thanks. – Joop Eggen Apr 16, 2018 at 13:39

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
                OP wanted to avoid checking the condition twice - if the exist condition is true, no need to check ifNotExist
– Eran
                Apr 16, 2018 at 12:28
                @Eran If it's a boolean flag, I see no reason to bother to over-engineer anything. Still, I've updated my answer.
– Michael
                Apr 16, 2018 at 12:31
                yes, it's exactly that I want to use fluent interface, but with you solution, if I do not check otherwise, I cannot chain other method of element, for ex: element.ifExist(...).otherElementMethod()
– yelliver
                Apr 16, 2018 at 18:14

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
                Thank you for your answer, this is good approach, but actually I want to use fluent style, this is not my expectation
– yelliver
                Apr 16, 2018 at 18:11
                @yelliver Why do you want a "fluent style"? What problem does it solve? This answer has the virtue of being much simpler and more straightforward and easier to use. You should have a very good reason to complicate things. (Note that this means you need a very good reason not to just use the if/else syntax in the first place.)
– jpmc26
                Apr 16, 2018 at 21:50
                @yelliver I'd like to note that I think this answer fits better with the example you edited in than a fluent interface does.
– jpmc26
                Apr 17, 2018 at 3:40

(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();
                    Why is getOperand().otherElementMethod() better than a second statement element.otherElementMethod() after the conditional stuff?
    – Michael
                    Apr 16, 2018 at 22:09
                    @Michael, It would be nearly the same, but OP wants to form chains. About Predicate - you're right, thanks
    – Andrew Tobilko
                    Apr 17, 2018 at 8:33
    

    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 ......

    LinkedHashMap should be used instead of HashMap. If i=9, with HashMap you cannot guarantee i < 10 will be evaluated before i < 100, so if you expect "Less than 10!" you could instead get "Less than 100!". With LinkedHashMap, conditions are evaluated in the order you put in the map, so with i=9 will return "Less than 10!" – Nitish Borade Oct 11, 2021 at 17:04

    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.