获取符合条件的流的第一个元素

202

如何在流中获取符合条件的第一个元素?我尝试了这个方法,但不起作用。

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;
}

}
3个回答

369

这可能是您正在寻找的内容:

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

更好的做法是,如果可能没有匹配的元素,那么get()将抛出NPE。因此使用:

而更好的方法是,如果存在可能无法匹配的元素,则get()会抛出NPE异常。所以请使用:

yourStream
    .filter(/* your criteria */)
    .findFirst()
    .orElse(null); /* You could also create a default object here */
一个例子:
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()
            .orElse(null);

    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.

你能给我一个关于Criteria的例子吗?它应该代表类似以下的内容: for(Stop s:listofstops){ if(s.name.equals("Linz") return r } - user2147674
1
Stops是另一个类,在Train中调用了filter方法,但我想遍历SortedSet stops的所有Stop元素。 - user2147674
2
原来我错了 - 惰性流可以避免低效率:https://dev59.com/O2Ag5IYBdhLWcg3wWp3- - Skystrider
4
你可以使用 .findFirst().orElse(yourBackUpGoesHere);。这也可以为 _null_。.findFirst().orElse(null); - ifloop
3
findFirst()返回一个Optional对象,可能为空。在这种情况下,调用get()会抛出NPE异常。为了防止这种情况发生,应该使用orElse()而不是get(),并提供一个备选对象(例如 orElse(new Station("dummy", -1))),或者将findFirst()的结果存储在一个变量中,并在调用get()之前检查它是否为空,可以使用isEmpty()进行检查。 - ifloop
显示剩余15条评论

10

当您编写lambda表达式时,->左侧的参数列表可以是带括号的参数列表(可能为空),也可以是一个不带任何括号的单个标识符。但在第二种形式中,该标识符不能使用类型名称声明。因此:

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));

如果编译器有足够的信息来推导出类型,那么这也是正确的。

使用第二个选项时,我会收到一个“创建本地变量”的消息。 - user2147674
@user2147674 这是一个错误信息吗?还是编译器只是告诉你它正在创建一个新的“局部变量” s 与 lambda 一起使用?在我看来,这似乎并不像一个错误,但显然我没有使用和你相同的编译器。 - ajb
1
@user2147674 这很奇怪。我能够使用第二个例子(在filter之后应用findFirst().get()),而且我没有收到任何错误。第三个例子对我也有效。 - ajb
@ajb 或许我从来都不是第一个,所以我看不到任何像“第一”这样的东西。 - Prabhat Gaur

9

我认为这是最好的方法:

this.stops.stream().filter(s -> Objects.equals(s.getStation().getName(), this.name)).findFirst().orElse(null);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接