Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java stream find value by key if exists

I'm having simple DataStructure

public class DataStructure {
    private String key;
    private String value;
    //get, set
}

And I need to return value from `List' based on key and I want to do it Java8 way, with streams. I think code speaks for himself:

public class Main {
    public static void main(String args[]) {
      List<DataStructure> dataList = new ArrayList<>();
      dataList.add(new DataStructure("first", "123"));
      dataList.add(new DataStructure("second", "456"));

        System.out.println(findValueOldSchool(dataList, "third")); //works ok
        System.out.println(findValueStream(dataList, "third")); //throws NoSuchElementException
    }

    static String findValueOldSchool(List<DataStructure> list, String key) {
        for (DataStructure ds : list) {
            if (key.equals(ds.getKey())) {
                return ds.getValue();
            }
        }
        return null;
    }

    static String findValueStream(List<DataStructure> list, String key) {
        return list.stream()
                .filter(ds -> key.equals(ds.getKey()))
                .findFirst()
                .get().getValue();
    }
}

How can I modify findValueStream() to not throw NoSuchValueException while I search for non existing key? I don't want to return Optional<String> because this method is already used in a lot of places in project. And, ofcourse I'v tried map, ifPresent, anyMatch, just can't find the right way to do it.

like image 278
JohnDoe Avatar asked Oct 16 '25 18:10

JohnDoe


2 Answers

You shall use Stream.findFirst with an Optional.orElse like :

static String findValueStream(List<DataStructure> list, String key) {
    return list.stream() // initial Stream<DataStructure>
            .filter(ds -> key.equals(ds.getKey())) // filtered Stream<DataStructure>
            .map(DataStructure::getValue) // mapped Stream<String>
            .findFirst() // first Optional<String>
            .orElse(null); // or else return 'null'
}

Note: The above uses the Stream.map to map the stream of DataStructure to a corresponding stream of value.

like image 97
Naman Avatar answered Oct 19 '25 06:10

Naman


use orElse to return a default value if the Optional has an empty state:

This also means you'll need to map to DataStructure::getValue first like so:

return list.stream()
           .filter(ds -> key.equals(ds.getKey()))
           .findFirst()
           .map(DataStructure::getValue)
           .orElse(null);

just replacing get with orElse will not suffice:

 return list.stream()
            .filter(ds -> key.equals(ds.getKey()))
            .findFirst()
            .orElse(null)
            .getValue();

As this time you'll get a NullPointerException instead of a NoSuchElementException in the case of an empty optional.

like image 20
Ousmane D. Avatar answered Oct 19 '25 07:10

Ousmane D.