доступ к полям внутри лямбда-выражения Java 8 - PullRequest
0 голосов
/ 02 ноября 2018

Пишу реализацию линейного поиска. Я написал код, используя также Java 7 и 8.

Ниже мой код:

int[] arr = new int[] { 12, 34, 94, 8, 37, 10 };
System.out.println("Enter the element to search: ");
Scanner scan = new Scanner(System.in);
int element = scan.nextInt();
boolean found = false;

// Linear search implementation using Java 7 features
for (int i = 0; i < arr.length; i++) {
    if (element == arr[i]) {
        int n = element;
        System.out.println("Element : "+n+" has been found at the index : "+i);
        found = true;
        break;
    }
}

// Linear search implementation using Java 8 features
IntStream.range(0, arr.length)
    .forEach(i -> {
        if (element == arr[i]) {
            int n = element;
            System.out.println("Element : " + n + " has been found at the index : " + i);
            found = true;
            break;
        }
    });

if (!found) {
    System.out.println("Element : "+ element + " not found.");
}

Следующий фрагмент кода работает правильно:

for (int i = 0; i < arr.length; i++) {
    if (element == arr[i]) {
        int n = element;
        System.out.println("Element : " + n + " has been found at the index : " + i);
        found = true;
        break;
    }
}

Но приведенный ниже код с функциями Java 8 выдает ошибку для полей внутри цикла forEach

IntStream.range(0, arr.length)
    .forEach(i -> {
        if (element == arr[i]) {
            int n = element;
            System.out.println("Element : " + n + " has been found at the index : " + i);
            found = true;
            break;
        }
    });

Произошла ошибка:

Найденная локальная переменная, определенная во включающей области видимости, должна быть окончательной или фактически конечной

разрыв не может быть использован вне контура или переключателя

Как получить доступ к boolean found внутри блока forEach в функциях Java 8?

Ответы [ 3 ]

0 голосов
/ 02 ноября 2018

На самом деле сообщение уже говорит об этом. Обратите внимание, что при работе с потоками вы обычно стараетесь избегать .forEach (или, по крайней мере, вы не просто преобразуете свои for -лопы в .forEach).

То, что вы, скорее всего, скорее всего хотели, выглядит примерно так:

IntStream.range(0, arr.length)
        .filter(i -> element == arr[i]) // .equals( ??
        .findFirst()
        .ifPresent(i -> System.out.println("Element : "+element+" has been found at the index : "+i));

Если вам приходится иметь дело также с делом, в котором ничего не найдено, используйте следующее:

OptionalInt result = IntStream.range(0, arr.length)
        .filter(i -> element == arr[i]) // .equals( ??
        .findFirst();
if (result.isPresent()) {
  System.out.printf("Element : %s has been found at the index : %d%n", element, result.getAsInt());
} else {
  // none found
  System.out.printf("Element %s not found%n", element);
}

Более новые версии Java поддерживают ifPresentOrElse, что может быть полезно здесь, например. (код протестирован MC Emperor, поскольку у меня нет Java> 8 здесь; -)):

...
.findFirst()
.ifPresentOrElse(i -> System.out.printf("Element : %s has been found at the index : %d%n", element, i),
                () -> System.out.printf("Element %s not found%n", element));
0 голосов
/ 02 ноября 2018

Есть несколько способов сделать это, в зависимости от ваших точных требований:

Индексы

Конечно, вы можете создать IntStream, содержащий все индексы данного массива:

IntStream.range(0, arr.length)

Затем вы можете проверить, равен ли элемент в данной позиции element:

    .filter(i -> arr[i] == element)

Мы можем прервать ходьбу, если найдем любой элемент массива, равный element:

    .findAny()

Возвращает OptionalInt, который содержит первый индекс найденного элемента. OptionalInt предназначен для того, чтобы содержать либо значение, либо нет. Это лучше, чем использование значения часового (например, -1).

Затем вы можете выполнить определенное действие, если найдено значение:

    .ifPresent(i -> System.out.println("Element " + element + " found at index " + i))

Поток над элементами без использования индекса

Если вас не интересует фактический индекс, вы также можете напрямую передавать массив. Класс Arrays в пакете java.util предоставляет метод для потоковой передачи int[], возвращая IntStream, который является потоком, предназначенным для потоковой передачи источника int s.

Arrays.stream(arr)
    .filter(t -> t == element)
    .findAny()
    .ifPresent(t -> ...);

Подробнее о потоках

Элементы потока лениво расходуются. Это означает, что поток завершается, если для достижения конечного результата используется достаточно элементов Например, Arrays.stream(arr).findAny() касается только первого элемента arr. Можно сказать, что findAny() похож на if (found) { break; } по своему действию.


Обратите внимание, что вы на самом деле используете лямбда-выражение . Это новая языковая конструкция, представленная в Java 8. forEach - это не более чем метод, принимающий Consumer, который, в свою очередь, является функциональным интерфейсом . Вы можете только получить доступ к переменным, которые final или фактически являются окончательными . Метод forEach отличается от цикла for, поэтому вы не можете использовать break.

0 голосов
/ 02 ноября 2018

Вы не должны обращаться к boolean found, а возвращать это значение из потока.

int element;
OptionalInt valueOptional = Arrays.stream(arr)
                                 .filter(current -> current == element)
                                 .findFirst();

Затем проверьте, присутствует ли опционально или нет.

valueOptional.isPresent();
...