简体   繁体   中英

How to filter objects using streams by their attributes?

Hello there my fellow programmers, recently is school we were asked to learn streams API, and i fell in love with them. Unfortunately I'm not skilled enough for the proper usage of them. I need to use streams to filter trough around 23 Buildings (treated as Objects) by their respective attributes. Let me demonstrate: Here is my Building class:

class Building  {
    String color;
    int position;
    int cost;
    int rent;
    int owner;

//ArrayList for storing all of the buildings
    public static ArrayList<Building> Buildings = new ArrayList<>();

//getter of the position of this building
    public int getBuildingPosition() {
        return position;
    }

//constructor:
    public Building(int position, int cost, int rent, String color, int owner) {
        Buildings.add(this);
    }
}

And here is an example of my Building object

Building buld1 = new Building(1, 50, 6, "gray", 0);

Now here comes the fun, because when i tried to filter it trough this stream code:

public static Building getBuildingByPosition(int pos) {
        List<Building> all = Building.Buildings
        .stream()
        .filter(x -> x.getBuildingPosition() == pos) // here may be the error
        .collect(Collectors.toList());
        return all.get(0);
    }

it returned an exception Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0 . It seems like my .filter() is incorrectly written, so it doesn't pass any elements.

Can somebody show me how to filter it properly please?

First you add the Building to your static list but you're not initializing this object, the fields are all empty

public Building(int position, int cost, int rent, String color, int owner) {
    this.position = position;
    this.cost = cost;
    this.rent = rent;
    this.color = color;
    this.owner = owner;
    Buildings.add(this);
}

If you want to return only one object satisfying your filter use findFirst that return an Optional

public static Building getBuildingByPosition(int pos) {
    Optional<Building> building = Building.Buildings
    .stream()
    .filter(x -> x.getBuildingPosition() == pos)
    .findFirst();
    return building.orElse(null);
}

Problem is in the following line return all.get(0);

You try to access element with index 0 but list is empty because none of the objects match filter criteria.

If there should either be 0 or 1 objects with at given position then you could use write something like this:

public static Optional<Building> getBuildingByPosition(int pos) {
    Optional<Building> buildingAtPos= Building.Buildings
    .stream()
    .filter(x -> x.getBuildingPosition() == pos) 
    .findFirst();
    return buildingAtPos;
}

Note that now we wrap Building inside Optional , this is commonly used in situations where there might or might not be value present.

If you always want to return Building or null if there isn't any building you could write it like this, but first solution is suggested way to do it:

public static Optional<Building> getBuildingByPosition(int pos) {
    Optional<Building> buildingAtPos= Building.Buildings
    .stream()
    .filter(x -> x.getBuildingPosition() == pos) 
    .findFirst();
    return buildingAtPos.orElse(null);
}

Another option you could use if you want to enforce presence of that building:

public static Optional<Building> getBuildingByPosition(int pos) {
    Optional<Building> buildingAtPos= Building.Buildings
    .stream()
    .filter(x -> x.getBuildingPosition() == pos) 
    .findFirst();
    return buildingAtPos.orElseThrow(()-> new IllegalStateException("Building at position " + pos + " must exist"));
}

Your filter are correct. I thin Building class constructor. Please set member variable for filter.

//constructor:
public Building(int position, int cost, int rent, String color, int owner) {
    this.position = position;
    Buildings.add(this);
}

the problem was the list was empty and you were trying to access the first element which doesn't exists. you can use findAny or findFirst which returns optional to avoid accessing a potentially null object, which allows you to set a default value if the object is null

return Building.Buildings
                .stream()
                .filter(x -> x.getBuildingPosition() == pos)
                .findAny().orElse(null);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM