Возврат значения из метода в выражении лямбда
Я пытаюсь выяснить, как вернуть значение метода из выражения лямбда:
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;
}
Однако, кажется, что использование ключевого слова return
в выражении лямбда будет явно возвращаться к самой лямбда-функции. Есть ли какой-либо способ разбить или принудительно вернуть весь метод?
Ответы
Ответ 1
Есть ли способ разбить или принудительно вернуть весь метод?
Нет. По крайней мере, если вы не сделаете исключение.
В принципе, это не то, что означает forEach
. Вы можете написать метод, который принял функцию, которая вернула бы null
для "keep going" и non-null для "stop" и сделать это результатом "... но этот метод не является forEach
.
Тот факт, что вы используете выражение лямбда, действительно случайный здесь. Представьте, что вы просто вызывали forEach
и передавали некоторый аргумент - не было бы действительно странно, если бы этот вызов заставлял ваш метод findMissingNumber
возвращаться (без исключения), без самого метода findMissingNumber
, имеющего оператор return?
Ответ 2
(Является ли это экземпляром проблемы XY?)
Вопрос о том, как вернуться из лямбда внутри forEach
. Jon Skeet предоставил некоторую полезную информацию о findFirst
, а также предупредил о побочных эффектах в параллельном параллельном лямбда-режиме - обе отличные точки.
Но в отношении исходного вопроса я все еще думаю: какая проблема вы пытаетесь решить?
Имя метода findMissingNumber
в этом примере наводит на размышления. Метод принимает набор чисел в качестве параметра и выполняет итерацию по нему при увеличении счетчика. Он возвращается, когда он находит несоответствие, или возвращает -1, если нет несоответствия. Поскольку счетчик увеличивается один раз, когда каждое значение в коллекции ints
обрабатывается, похоже, что эта коллекция должна быть в порядке, если только номер отсутствует.
Если это так, параметр должен быть List
вместо Collection
. (Сделаем здесь большое предположение.) В этом предположении можно переписать код с использованием lambdas в виде потоков следующим образом:
static OptionalInt findMissingNumber(List<Integer> ints) {
return
IntStream.rangeClosed(1, ints.size())
.filter(i -> i != ints.get(i-1))
.findFirst();
}
Вместо того, чтобы увеличивать счетчик, мы используем IntStream.range
для генерации ожидаемых значений в списке. Затем мы полагаемся на случайный доступ к списку до значений get
из их ожидаемых позиций в списке. Мы фильтруем для несоответствий и возвращаем первый, если таковой имеется. Это позволяет избежать мутации и поэтому должно работать правильно параллельно. (Обратите внимание, что это не очень хорошо распараллеливается, если список не является произвольным доступом.)
Возвращаемое значение представляет собой OptionalInt
, который является пустым, если не найдено никакого несоответствия. Это более явное, чем использование значения часового типа, например -1
, чтобы указать условие "не найдено".