Получить первый элемент, соответствующий критериям

122

Как получить первый элемент, соответствующий критерию в потоке? Я пробовал это, но не работает

this.stops.stream().filter(Stop s-> s.getStation().getName().equals(name));

Этот критерий не работает, метод фильтра вызывается не в классе Stop.

public class Train {

private final String name;
private final SortedSet<Stop> stops;

public Train(String name) {
    this.name = name;
    this.stops = new TreeSet<Stop>();
}

public void addStop(Stop stop) {
    this.stops.add(stop);
}

public Stop getFirstStation() {
    return this.getStops().first();
}

public Stop getLastStation() {
    return this.getStops().last();
}

public SortedSet<Stop> getStops() {
    return stops;
}

public SortedSet<Stop> getStopsAfter(String name) {


    // return this.stops.subSet(, toElement);
    return null;
}
}


import java.util.ArrayList;
import java.util.List;

public class Station {
private final String name;
private final List<Stop> stops;

public Station(String name) {
    this.name = name;
    this.stops = new ArrayList<Stop>();

}

public String getName() {
    return name;
}

}
user2147674
источник

Ответы:

215

Это может быть то, что вы ищете:

yourStream
    .filter(/* your criteria */)
    .findFirst()
    .get();



Пример:

public static void main(String[] args) {
    class Stop {
        private final String stationName;
        private final int    passengerCount;

        Stop(final String stationName, final int passengerCount) {
            this.stationName    = stationName;
            this.passengerCount = passengerCount;
        }
    }

    List<Stop> stops = new LinkedList<>();

    stops.add(new Stop("Station1", 250));
    stops.add(new Stop("Station2", 275));
    stops.add(new Stop("Station3", 390));
    stops.add(new Stop("Station2", 210));
    stops.add(new Stop("Station1", 190));

    Stop firstStopAtStation1 = stops.stream()
            .filter(e -> e.stationName.equals("Station1"))
            .findFirst()
            .get();

    System.out.printf("At the first stop at Station1 there were %d passengers in the train.", firstStopAtStation1.passengerCount);
}

Выход:

At the first stop at Station1 there were 250 passengers in the train.
ifloop
источник
Не могли бы вы привести мне пример критериев? Он должен представлять что-то вроде for (Stop s: listofstops) {if (s.name.equals ("Linz") return r}
user2147674
1
Stops - это еще один класс, фильтр метода вызывается в Train, но я хочу пройти по всем элементам Stop остановок
SortedSet
2
Оказывается, я ошибаюсь - ленивые потоки предотвращают неэффективность: stackoverflow.com/questions/23696317/…
Skychan 02
2
@alexpfx вы можете использовать .findFirst().orElse(yourBackUpGoesHere);. Это также может быть нулевым .findFirst().orElse(null);
ifloop
1
@iammrmehul No. findFirst()возвращает необязательный объект ( JavaDoc ), который может быть пустым. В этом случае вызов get()вызовет NPE. Чтобы этого не произошло, используйте orElse()вместо get()и предоставьте резервный объект (например orElse(new Station("dummy", -1)) или сохраните результат findFirst()в переменной и проверьте его isEmpty()перед вызовомget()
ifloop
7

Когда вы пишете лямбда-выражение, список аргументов слева от него ->может быть либо списком аргументов в скобках (возможно, пустым), либо одним идентификатором без скобок. Но во второй форме идентификатор не может быть объявлен с именем типа. Таким образом:

this.stops.stream().filter(Stop s-> s.getStation().getName().equals(name));

неверный синтаксис; но

this.stops.stream().filter((Stop s)-> s.getStation().getName().equals(name));

правильно. Или:

this.stops.stream().filter(s -> s.getStation().getName().equals(name));

также является правильным, если у компилятора достаточно информации для определения типов.

AJB
источник
Со вторым я получаю сообщение "create local var" s
user2147674 08
@ user2147674 Это сообщение об ошибке? Или компилятор просто сообщает вам, что он создает новую разновидность «локальной переменной» sдля использования с лямбда-выражением? Для меня это не похоже на ошибку, но я, по-видимому, не использую тот же компилятор, что и вы.
ajb
1
@ user2147674 Это довольно странно. Я могу использовать второй пример (с findFirst().get()примененным послеfilter ) и не получаю никаких ошибок. Третий пример мне тоже подходит.
ajb 08
3

Думаю, это лучший способ:

this.stops.stream().filter(s -> Objects.equals(s.getStation().getName(), this.name)).findFirst().orElse(null);
Мартин Волек
источник