Better Filtering on Java Streams I need to run filtering on nested Lists and return a List of items from back 

I will put a sample code here with my model

import lombok.Data;

import java.util.List;
import java.util.stream.Collectors;

class Scratch {
    public static void main(String[] args) {

        ParentModel parent = new ParentModel();
        List&lt;Information&gt; informationList = parent.getChildDatas().stream()
                //Filtering null &amp;&amp; empty grandchild
                .filter(childData -&gt; childData.getGrandChildDatas() !=null &amp;&amp; !childData.getGrandChildDatas().isEmpty())
                .flatMap(childData -&gt; childData.getGrandChildDatas().stream() )
                //Filtering null &amp;&amp; empty information
                .filter(grandChild -&gt; grandChild.getInformations() !=null &amp;&amp; !grandChild.getInformations().isEmpty())
                .flatMap(grandChild-&gt; grandChild.getInformations().stream())
                //filtering key
                .filter(information -&gt; information.getKey().equals("SOMETHING"))
                .collect(Collectors.toList());

    }

    @Data
    static class ParentModel {
        private List&lt;ChildModel&gt; childDatas;
    }

    @Data
    static class ChildModel {
        private List&lt;GrandChildModel&gt; grandChildDatas;
    }

    @Data
    static class GrandChildModel {
        private List&lt;Information&gt; informations;
    }

    @Data
    static class Information{
        private String info1;
        private String info2;
        private String key;
    }
}


So here you can see, I'm filtering and mapping it back to child streams two times.

Is there alternate way to achieve what I'm trying to do here ??
First, you should avoid using null to represent an empty list.  Use an actual empty list, or even Collections.emptyList(), which is a immutable singleton.  This will avoid the need for null checks. 

Second, you are filtering by getting a sub attribute, checking conditions on that object, then requesting the same sub attribute in the next step.  Instead, you should map to the sub attribute, then filter &amp; process. 

    ...
    .map(ChildModel::getChildrenDatas)
    .filter(data -&gt; data != null &amp;&amp; !data.isEmpty())
    .flatMap(List::stream)
    ...


Third, the .isEmpty() check is unnecessary, as .flatMap works fine with an empty stream. 

   ...
    .map(ChildModel::getChildrenDatas)
    .filter(Objects::nonNull)
    .flatMap(List::stream)
    ...


Again, if you don’t use null to represent empty lists, the filter line can be removed entirely.