Anna Klein
Anna Klein

Reputation: 2171

Method call on a Lambda object returns value

the expression this.apply(stringValue) returns true on a lambda expression j8Test.PerformChange$$Lambda$2/284720968@2f4d3709

Why does it return true and not false. And why doest it return actually anything at all? (I am not talking about all other objects of type PerformChangeImpl)

private final List<PerformChange> performChangeList = Arrays.asList(
        new PerformChangeImpl("1"),
        new PerformChangeImpl("2"),
        new PerformChangeImpl("3")
);

@FunctionalInterface
interface PerformChange extends Function<String, Boolean> {

    default PerformChange performChange(PerformChange input) {
        System.out.println("1 this: " + this);
        System.out.println("2 input: " + input);
        return stringValue -> {
            System.out.println("\n3 this: " + this);
            System.out.println("4 input: " + input);
            if (this.apply(stringValue)) {
                System.out.println("5 this: " + this);
                return input.apply(stringValue);
            }
            return false;
        };
    }
}

class PerformChangeImpl implements PerformChange {

    private final String value;

    public PerformChangeImpl(String value) {
        this.value = value;
    }

    @Override
    public Boolean apply(String string) {
        System.out.println("\n6: " + this);
        System.out.println("7: " + string);
        return true;
    }

    @Override
    public String toString() {
        return "obj id: " + value;
    }
}

and

private void executePerformChanges() {
    System.out.println(performChangeList.stream()
            .reduce(PerformChange::performChange)
            .orElse(new PerformChangeImpl("4"))
            .apply("test"));
}

result in

1 this: obj id: 1
2 input: obj id: 2
1 this: j8Test.PerformChange$$Lambda$2/284720968@2f4d3709
2 input: obj id: 3

3 this: j8Test.PerformChange$$Lambda$2/284720968@2f4d3709
4 input: obj id: 3

3 this: obj id: 1
4 input: obj id: 2

6: obj id: 1
7: test
5 this: obj id: 1

6: obj id: 2
7: test
5 this: j8Test.PerformChange$$Lambda$2/284720968@2f4d3709

6: obj id: 3
7: test
true

Process finished with exit code 0

Upvotes: 3

Views: 1721

Answers (2)

Andrew
Andrew

Reputation: 49606

You've got two implementations of PerformChange:

  1. The class PerformChangeImpl which functional method apply always returns true. There is no chance to get false.
  2. The lambda expression str -> apply(str) && input.apply(str) which you are generating in performChange (I simplified it a bit). There is a chance to get false if either apply(str) or input.apply(str) returns false.

Since performChangeList contains only PerformChangeImpl instances, the generated lambda could be simplified to input.apply(str), In other words, the method would look like

default PerformChange performChange(PerformChange input) {
    // str -> apply(str) && input.apply(str)
    // str -> true && input.apply(str)
    // str -> input.apply(str)
    // input::apply
    // input
    return input;
}

and the resulting true is expected for any given String as long as performChangeList is populated exclusively with PerformChangeImpl objects.

As a side note, Function<String, Boolean> is simply Predicate<String> and it's better to use the latter.

@FunctionalInterface
interface PerformChange extends Predicate<String> { ... }

class PerformChangeImpl implements PerformChange {
    @Override
    public boolean test(String string) { ... }
}

Upvotes: 2

GhostCat
GhostCat

Reputation: 140427

Here:

public Boolean apply(String string) {
  ...

Your class PerformChangeImpl overrides the apply() method. That is the core of the Function interface.

And in the end, your code calls:

.apply("test"))

And the very last statement within apply() is:

return true;

The method returns true, because you told it to do so. So you should either change that method body to return true / false based on some condition, or you shouldn't be calling apply() in the end.

And note: this becomes really obvious from the print statements. In the end, you get 6 and 7, which you print within the apply() of the PerformChangeImpl class.

Also note: your defaulted method does:

if(this.apply(stringValue)) { 

That calls apply() on the "surrounding" PerformChangeImpl ... and will return true.

Upvotes: 4

Related Questions