Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning a value from a method within a lambda expression

I'm trying to figure out how to return a method value from a lambda expression:

public int findMissingNumber(Collection<Integer> ints) {
    Single<Integer> start = new Single<>(1);
    ints.stream().mapToInt(Integer::valueOf).parallel().forEach(i -> {
        if (i != start.setValue(start.getValue() + 1)) {
            //return here
        }
    });
    return -1;
}

However, it seems that using the return keyword in the lambda expression will explicitly return to the lambda function itself. Is there some type of way to break or force a return for the entire method?

like image 373
Rogue Avatar asked Jul 11 '14 19:07

Rogue


People also ask

How do you return a value in lambda?

Lambda functions are syntactically restricted to return a single expression. You can use them as an anonymous function inside other functions. The lambda functions do not need a return statement, they always return a single expression.

Can you return in a lambda expression?

A return statement is not an expression in a lambda expression. We must enclose statements in braces ({}). However, we do not have to enclose a void method invocation in braces. The return type of a method in which lambda expression used in a return statement must be a functional interface.

How do you call a method in lambda?

Thus, a lambda expression results in a form of anonymous class. In a method reference, you place the object (or class) that contains the method that you want to call before the delimiter :: operator and the name of the method is provided after it without arguments.

What is return type of lambda expression?

What is the return type of lambda expression? Explanation: Lambda expression enables us to pass functionality as an argument to another method, such as what action should be taken when someone clicks a button. 4.


2 Answers

Is there some type of way to break or force a return for the entire method?

No. At least, not unless you throw an exception.

Basically, that's not what forEach is meant for. You could write a method which accepted a function which would return null for "keep going" and non-null for "stop, and make this the result"... but that method isn't forEach.

The fact that you're using a lambda expression is really incidental here. Imagine you were just calling forEach and passing in some argument - wouldn't it be really weird if that call made your findMissingNumber method return (without an exception), without the findMissingNumber method itself having the return statement?

like image 76
Jon Skeet Avatar answered Oct 20 '22 06:10

Jon Skeet


(Is this an instance of the XY problem?)

The question is about how to return from a lambda inside a forEach. Jon Skeet provided some useful information about findFirst and also cautioned about side effects in a lambda run in parallel -- both excellent points.

But regarding the original question, I'm still thinking: what problem are you trying to solve?

The method name findMissingNumber in the example is suggestive. The method takes a collection of numbers as a parameter and iterates over it while incrementing a counter. It returns when it finds a mismatch, or it returns -1 if there is no mismatch. Since the counter is incremented once as each value in the ints collection is processed, it seems like that collection is expected to be in order, unless a number is missing.

If so, the parameter ought to be a List instead of a Collection. (Making a big assumption here.) Under this assumption, one could rewrite the code using lambdas as streams like so:

static OptionalInt findMissingNumber(List<Integer> ints) {
    return
        IntStream.rangeClosed(1, ints.size())
            .filter(i -> i != ints.get(i-1))
            .findFirst();
}

Instead of incrementing a counter, we use IntStream.range to generate the values expected to be in the list. We then rely on random access to the list to get values from their expected positions in the list. We filter for the mismatches and return the first one, if any. This avoids mutation and so should run correctly in parallel. (Note that this doesn't parallelize well if the list isn't random-access, though.)

The return value is an OptionalInt which is empty if no mismatch was found. This is more explicit than using a sentinel value like -1 to indicate the "not found" condition.

like image 26
Stuart Marks Avatar answered Oct 20 '22 05:10

Stuart Marks