Obtener el primer elemento que coincida con los criterios

121

¿Cómo obtener el primer elemento que coincide con un criterio en una secuencia? He intentado esto pero no funciona

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

Ese criterio no funciona, el método de filtro se invoca en una clase distinta a 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;
}

}
usuario2147674
fuente

Respuestas:

213

Esto podría ser lo que estás buscando:

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



Un ejemplo:

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

La salida es:

At the first stop at Station1 there were 250 passengers in the train.
ifloop
fuente
¿Puede darme un ejemplo de Criteria, por favor? Debería representar algo como for (Stop s: listofstops) {if (s.name.equals ("Linz") return r}
user2147674
1
Stops es otra clase, el filtro de método se invoca en Train pero quiero recorrer todos los elementos Stop de las paradas
SortedSet
2
Resulta que estoy equivocado: las transmisiones perezosas evitan la ineficiencia: stackoverflow.com/questions/23696317/…
Skychan
2
@alexpfx puede usar .findFirst().orElse(yourBackUpGoesHere);. Eso también puede ser nulo .findFirst().orElse(null);
ifloop
1
@iammrmehul No. findFirst()devuelve un objeto opcional ( JavaDoc ), que puede estar vacío. En este caso, la llamada a get()lanzará el NPE. Para evitar que eso suceda, use en orElse()lugar de get()y proporcione un objeto de respaldo (como orElse(new Station("dummy", -1)), o almacene el resultado de findFirst()en una variable y isEmpty()get()
verifíquelo
7

Cuando escribe una expresión lambda, la lista de argumentos a la izquierda de ->puede ser una lista de argumentos entre paréntesis (posiblemente vacía) o un identificador único sin paréntesis. Pero en la segunda forma, el identificador no se puede declarar con un nombre de tipo. Así:

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

es una sintaxis incorrecta; pero

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

es correcto. O:

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

también es correcto si el compilador tiene suficiente información para averiguar los tipos.

ajb
fuente
Con el segundo, recibo un mensaje "create local var" s
user2147674
@ user2147674 ¿Es un mensaje de error? ¿O el compilador solo le informa que está creando un nuevo tipo de "variable local" spara usar con el lambda? Realmente no me parece un error, pero aparentemente no estoy usando el mismo compilador que tú.
ajb
1
@ user2147674 Eso es bastante extraño. Puedo usar el segundo ejemplo (con findFirst().get()aplicado después filter) y no obtengo ningún error. El tercer ejemplo también me funciona.
ajb
3

Creo que esta es la mejor manera:

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