Java 8 list processing - add elements conditionally












8














I have the following piece of code:



List<Object> list = new ArrayList<>();
list.addAll(method1());
if(list.isEmpty()) { list.addAll(method2()); }
if(list.isEmpty()) { list.addAll(method3()); }
if(list.isEmpty()) { list.addAll(method4()); }
if(list.isEmpty()) { list.addAll(method5()); }
if(list.isEmpty()) { list.addAll(method6()); }
return list;


Is there a nice way to add elements conditionally, maybe using stream operations? I would like to add elements from method2 only if the list is empty otherwise return and so on.



Edit: It's worth to mention that the methods contain heavy logic so need to be prevented from execution.










share|improve this question




















  • 1




    I don't think there's a faster way to do it.
    – gbandres
    1 hour ago
















8














I have the following piece of code:



List<Object> list = new ArrayList<>();
list.addAll(method1());
if(list.isEmpty()) { list.addAll(method2()); }
if(list.isEmpty()) { list.addAll(method3()); }
if(list.isEmpty()) { list.addAll(method4()); }
if(list.isEmpty()) { list.addAll(method5()); }
if(list.isEmpty()) { list.addAll(method6()); }
return list;


Is there a nice way to add elements conditionally, maybe using stream operations? I would like to add elements from method2 only if the list is empty otherwise return and so on.



Edit: It's worth to mention that the methods contain heavy logic so need to be prevented from execution.










share|improve this question




















  • 1




    I don't think there's a faster way to do it.
    – gbandres
    1 hour ago














8












8








8


1





I have the following piece of code:



List<Object> list = new ArrayList<>();
list.addAll(method1());
if(list.isEmpty()) { list.addAll(method2()); }
if(list.isEmpty()) { list.addAll(method3()); }
if(list.isEmpty()) { list.addAll(method4()); }
if(list.isEmpty()) { list.addAll(method5()); }
if(list.isEmpty()) { list.addAll(method6()); }
return list;


Is there a nice way to add elements conditionally, maybe using stream operations? I would like to add elements from method2 only if the list is empty otherwise return and so on.



Edit: It's worth to mention that the methods contain heavy logic so need to be prevented from execution.










share|improve this question















I have the following piece of code:



List<Object> list = new ArrayList<>();
list.addAll(method1());
if(list.isEmpty()) { list.addAll(method2()); }
if(list.isEmpty()) { list.addAll(method3()); }
if(list.isEmpty()) { list.addAll(method4()); }
if(list.isEmpty()) { list.addAll(method5()); }
if(list.isEmpty()) { list.addAll(method6()); }
return list;


Is there a nice way to add elements conditionally, maybe using stream operations? I would like to add elements from method2 only if the list is empty otherwise return and so on.



Edit: It's worth to mention that the methods contain heavy logic so need to be prevented from execution.







java collections java-8 stream






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 42 mins ago

























asked 1 hour ago









ionut

705




705








  • 1




    I don't think there's a faster way to do it.
    – gbandres
    1 hour ago














  • 1




    I don't think there's a faster way to do it.
    – gbandres
    1 hour ago








1




1




I don't think there's a faster way to do it.
– gbandres
1 hour ago




I don't think there's a faster way to do it.
– gbandres
1 hour ago












6 Answers
6






active

oldest

votes


















7














I would simply use a stream of suppliers and filter on List.isEmpty:



Stream.<Supplier<List<Object>>>of(() -> method1(), 
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6())
.map(Supplier<List<Object>>::get)
.filter(l -> !l.isEmpty())
.findFirst()
.ifPresent(list::addAll);

return list;


findFirst() will prevent unnecessary calls to methodN() when the first non-empty list is returned by one of the methods.



EDIT:

As remarked in comments below, if your list object is not initialized with anything else, then it makes sense to just return the result of the stream directly:



return  Stream.<Supplier<List<Object>>>of(() -> method1(), 
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6())
.map(Supplier<List<Object>>::get)
.filter(l -> !l.isEmpty())
.findFirst()
.orElseGet(ArrayList::new);





share|improve this answer



















  • 3




    Worth to note that, if methodX() returns a List and not another type of Collection, it might be possible to return that list directly, instead of creating a new list and adding to that: .map(Supplier::get).filter(s -> !s.isEmpty()).findFirst().orElse(emptyList());. Whether this is appropriate or not is not possible to determine from the question.
    – Magnilex
    40 mins ago










  • By the way, do you know why you have to explicitly state the type <Supplier<List<Object>>> to the factory method because the compiler cannot infer the type itself? I had the same issue.
    – Ricola
    28 mins ago










  • @Ricola Without defining it explicitly, the compiler doesn't know the target type of lambda expressions. The alternative would have been to do it in two steps, explicitly declaring a Stream<Supplier<List<Object>>> as the type of the stream.
    – ernest_k
    24 mins ago



















4














You could try to check the return value of addAll. It will return true whenever the list has been modified, so try this:



List<Object> list = new ArrayList<>();
// ret unused, otherwise it doesn't compile
boolean ret = list.addAll(method1())
|| list.addAll(method2())
|| list.addAll(method3())
|| list.addAll(method4())
|| list.addAll(method5())
|| list.addAll(method6());
return list;


Because of lazy evaluation, the first addAll operation that added at least one element will prevent the rest from bein called. I like the fact that "||" expresses the intent quite well.






share|improve this answer



















  • 1




    one of the rare cases where one cares about the return value of addAll. indeed very clever, efficient and readable! ;-).
    – Aomine
    11 mins ago








  • 1




    Agreed. I believe it can't get simpler or more readable than this.
    – ernest_k
    10 mins ago



















1














A way of doing it without repeating yourself is to extract a method doing it for you:



private void addIfEmpty(List<Object> targetList, Supplier<Collection<?>> supplier) {
if (targetList.isEmpty()) {
targetList.addAll(supplier.get());
}
}


And then



List<Object> list = new ArrayList<>();
addIfEmpty(list, this::method1);
addIfEmpty(list, this::method2);
addIfEmpty(list, this::method3);
addIfEmpty(list, this::method4);
addIfEmpty(list, this::method5);
addIfEmpty(list, this::method6);
return list;


Or even use a for loop:



List<Supplier<Collection<?>>> suppliers = Arrays.asList(this::method1, this::method2, ...);
List<Object> list = new ArrayList<>();
suppliers.forEach(supplier -> this.addIfEmpty(list, supplier));


Now DRY is not the most important aspect. If you think your original code is easier to read and understand, then keep it like that.






share|improve this answer























  • You should rather name the method addIfEmpty instead of addIfNotEmpty
    – Ricola
    35 mins ago










  • @Ricola good point, indeed.
    – JB Nizet
    23 mins ago



















1














You could create a method as such:



public static List<Object> lazyVersion(Supplier<List<Object>>... suppliers){
return Arrays.stream(suppliers)
.map(Supplier::get)
.filter(s -> !s.isEmpty()) // or .filter(Predicate.not(List::isEmpty)) as of JDK11
.findFirst()
.orElseGet(Collections::emptyList);
}


and then call it as follows:



lazyVersion(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6());


method name for illustration purposes only.






share|improve this answer































    1














    You could make your code nicer by creating the method



    public void addAllIfEmpty(List<Object> list, Supplier<List<Object>> method){
    if(list.isEmpty()){
    list.addAll(method.get());
    }
    }


    Then you can use it like this (I assumed your methods are not static methods, if they are you need to reference them using ClassName::method1)



    List<Object> list = new ArrayList<>();
    list.addAll(method1());
    addAllIfEmpty(list, this::method2);
    addAllIfEmpty(list, this::method3);
    addAllIfEmpty(list, this::method4);
    addAllIfEmpty(list, this::method5);
    addAllIfEmpty(list, this::method6);
    return list;




    If you really want to use a Stream, you could do this



     Stream.<Supplier<List<Object>>>of(this::method1, this::method2, this::method3, this::method4, this::method5, this::method6)
    .collect(ArrayList::new, this::addAllIfEmpty, ArrayList::addAll);


    IMO it makes it more complicated, depending on how your methods are referenced, it might be better to use a loop






    share|improve this answer































      0














      Java 8 streams weren't designed to support this kind of operation. From the jdk:



      A stream should be operated on (invoking an intermediate or terminal stream operation) only once. This rules out, for example, "forked" streams, where the same source feeds two or more pipelines, or multiple traversals of the same stream.



      If you can store it in memory you can use Collectors.partitioningBy if you have just two types and go by with a Map<Boolean, List>. Otherwise use Collectors.groupingBy.






      share|improve this answer





















        Your Answer






        StackExchange.ifUsing("editor", function () {
        StackExchange.using("externalEditor", function () {
        StackExchange.using("snippets", function () {
        StackExchange.snippets.init();
        });
        });
        }, "code-snippets");

        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "1"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53957780%2fjava-8-list-processing-add-elements-conditionally%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        6 Answers
        6






        active

        oldest

        votes








        6 Answers
        6






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        7














        I would simply use a stream of suppliers and filter on List.isEmpty:



        Stream.<Supplier<List<Object>>>of(() -> method1(), 
        () -> method2(),
        () -> method3(),
        () -> method4(),
        () -> method5(),
        () -> method6())
        .map(Supplier<List<Object>>::get)
        .filter(l -> !l.isEmpty())
        .findFirst()
        .ifPresent(list::addAll);

        return list;


        findFirst() will prevent unnecessary calls to methodN() when the first non-empty list is returned by one of the methods.



        EDIT:

        As remarked in comments below, if your list object is not initialized with anything else, then it makes sense to just return the result of the stream directly:



        return  Stream.<Supplier<List<Object>>>of(() -> method1(), 
        () -> method2(),
        () -> method3(),
        () -> method4(),
        () -> method5(),
        () -> method6())
        .map(Supplier<List<Object>>::get)
        .filter(l -> !l.isEmpty())
        .findFirst()
        .orElseGet(ArrayList::new);





        share|improve this answer



















        • 3




          Worth to note that, if methodX() returns a List and not another type of Collection, it might be possible to return that list directly, instead of creating a new list and adding to that: .map(Supplier::get).filter(s -> !s.isEmpty()).findFirst().orElse(emptyList());. Whether this is appropriate or not is not possible to determine from the question.
          – Magnilex
          40 mins ago










        • By the way, do you know why you have to explicitly state the type <Supplier<List<Object>>> to the factory method because the compiler cannot infer the type itself? I had the same issue.
          – Ricola
          28 mins ago










        • @Ricola Without defining it explicitly, the compiler doesn't know the target type of lambda expressions. The alternative would have been to do it in two steps, explicitly declaring a Stream<Supplier<List<Object>>> as the type of the stream.
          – ernest_k
          24 mins ago
















        7














        I would simply use a stream of suppliers and filter on List.isEmpty:



        Stream.<Supplier<List<Object>>>of(() -> method1(), 
        () -> method2(),
        () -> method3(),
        () -> method4(),
        () -> method5(),
        () -> method6())
        .map(Supplier<List<Object>>::get)
        .filter(l -> !l.isEmpty())
        .findFirst()
        .ifPresent(list::addAll);

        return list;


        findFirst() will prevent unnecessary calls to methodN() when the first non-empty list is returned by one of the methods.



        EDIT:

        As remarked in comments below, if your list object is not initialized with anything else, then it makes sense to just return the result of the stream directly:



        return  Stream.<Supplier<List<Object>>>of(() -> method1(), 
        () -> method2(),
        () -> method3(),
        () -> method4(),
        () -> method5(),
        () -> method6())
        .map(Supplier<List<Object>>::get)
        .filter(l -> !l.isEmpty())
        .findFirst()
        .orElseGet(ArrayList::new);





        share|improve this answer



















        • 3




          Worth to note that, if methodX() returns a List and not another type of Collection, it might be possible to return that list directly, instead of creating a new list and adding to that: .map(Supplier::get).filter(s -> !s.isEmpty()).findFirst().orElse(emptyList());. Whether this is appropriate or not is not possible to determine from the question.
          – Magnilex
          40 mins ago










        • By the way, do you know why you have to explicitly state the type <Supplier<List<Object>>> to the factory method because the compiler cannot infer the type itself? I had the same issue.
          – Ricola
          28 mins ago










        • @Ricola Without defining it explicitly, the compiler doesn't know the target type of lambda expressions. The alternative would have been to do it in two steps, explicitly declaring a Stream<Supplier<List<Object>>> as the type of the stream.
          – ernest_k
          24 mins ago














        7












        7








        7






        I would simply use a stream of suppliers and filter on List.isEmpty:



        Stream.<Supplier<List<Object>>>of(() -> method1(), 
        () -> method2(),
        () -> method3(),
        () -> method4(),
        () -> method5(),
        () -> method6())
        .map(Supplier<List<Object>>::get)
        .filter(l -> !l.isEmpty())
        .findFirst()
        .ifPresent(list::addAll);

        return list;


        findFirst() will prevent unnecessary calls to methodN() when the first non-empty list is returned by one of the methods.



        EDIT:

        As remarked in comments below, if your list object is not initialized with anything else, then it makes sense to just return the result of the stream directly:



        return  Stream.<Supplier<List<Object>>>of(() -> method1(), 
        () -> method2(),
        () -> method3(),
        () -> method4(),
        () -> method5(),
        () -> method6())
        .map(Supplier<List<Object>>::get)
        .filter(l -> !l.isEmpty())
        .findFirst()
        .orElseGet(ArrayList::new);





        share|improve this answer














        I would simply use a stream of suppliers and filter on List.isEmpty:



        Stream.<Supplier<List<Object>>>of(() -> method1(), 
        () -> method2(),
        () -> method3(),
        () -> method4(),
        () -> method5(),
        () -> method6())
        .map(Supplier<List<Object>>::get)
        .filter(l -> !l.isEmpty())
        .findFirst()
        .ifPresent(list::addAll);

        return list;


        findFirst() will prevent unnecessary calls to methodN() when the first non-empty list is returned by one of the methods.



        EDIT:

        As remarked in comments below, if your list object is not initialized with anything else, then it makes sense to just return the result of the stream directly:



        return  Stream.<Supplier<List<Object>>>of(() -> method1(), 
        () -> method2(),
        () -> method3(),
        () -> method4(),
        () -> method5(),
        () -> method6())
        .map(Supplier<List<Object>>::get)
        .filter(l -> !l.isEmpty())
        .findFirst()
        .orElseGet(ArrayList::new);






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 22 mins ago









        Aomine

        39.2k73669




        39.2k73669










        answered 57 mins ago









        ernest_k

        19.6k41941




        19.6k41941








        • 3




          Worth to note that, if methodX() returns a List and not another type of Collection, it might be possible to return that list directly, instead of creating a new list and adding to that: .map(Supplier::get).filter(s -> !s.isEmpty()).findFirst().orElse(emptyList());. Whether this is appropriate or not is not possible to determine from the question.
          – Magnilex
          40 mins ago










        • By the way, do you know why you have to explicitly state the type <Supplier<List<Object>>> to the factory method because the compiler cannot infer the type itself? I had the same issue.
          – Ricola
          28 mins ago










        • @Ricola Without defining it explicitly, the compiler doesn't know the target type of lambda expressions. The alternative would have been to do it in two steps, explicitly declaring a Stream<Supplier<List<Object>>> as the type of the stream.
          – ernest_k
          24 mins ago














        • 3




          Worth to note that, if methodX() returns a List and not another type of Collection, it might be possible to return that list directly, instead of creating a new list and adding to that: .map(Supplier::get).filter(s -> !s.isEmpty()).findFirst().orElse(emptyList());. Whether this is appropriate or not is not possible to determine from the question.
          – Magnilex
          40 mins ago










        • By the way, do you know why you have to explicitly state the type <Supplier<List<Object>>> to the factory method because the compiler cannot infer the type itself? I had the same issue.
          – Ricola
          28 mins ago










        • @Ricola Without defining it explicitly, the compiler doesn't know the target type of lambda expressions. The alternative would have been to do it in two steps, explicitly declaring a Stream<Supplier<List<Object>>> as the type of the stream.
          – ernest_k
          24 mins ago








        3




        3




        Worth to note that, if methodX() returns a List and not another type of Collection, it might be possible to return that list directly, instead of creating a new list and adding to that: .map(Supplier::get).filter(s -> !s.isEmpty()).findFirst().orElse(emptyList());. Whether this is appropriate or not is not possible to determine from the question.
        – Magnilex
        40 mins ago




        Worth to note that, if methodX() returns a List and not another type of Collection, it might be possible to return that list directly, instead of creating a new list and adding to that: .map(Supplier::get).filter(s -> !s.isEmpty()).findFirst().orElse(emptyList());. Whether this is appropriate or not is not possible to determine from the question.
        – Magnilex
        40 mins ago












        By the way, do you know why you have to explicitly state the type <Supplier<List<Object>>> to the factory method because the compiler cannot infer the type itself? I had the same issue.
        – Ricola
        28 mins ago




        By the way, do you know why you have to explicitly state the type <Supplier<List<Object>>> to the factory method because the compiler cannot infer the type itself? I had the same issue.
        – Ricola
        28 mins ago












        @Ricola Without defining it explicitly, the compiler doesn't know the target type of lambda expressions. The alternative would have been to do it in two steps, explicitly declaring a Stream<Supplier<List<Object>>> as the type of the stream.
        – ernest_k
        24 mins ago




        @Ricola Without defining it explicitly, the compiler doesn't know the target type of lambda expressions. The alternative would have been to do it in two steps, explicitly declaring a Stream<Supplier<List<Object>>> as the type of the stream.
        – ernest_k
        24 mins ago













        4














        You could try to check the return value of addAll. It will return true whenever the list has been modified, so try this:



        List<Object> list = new ArrayList<>();
        // ret unused, otherwise it doesn't compile
        boolean ret = list.addAll(method1())
        || list.addAll(method2())
        || list.addAll(method3())
        || list.addAll(method4())
        || list.addAll(method5())
        || list.addAll(method6());
        return list;


        Because of lazy evaluation, the first addAll operation that added at least one element will prevent the rest from bein called. I like the fact that "||" expresses the intent quite well.






        share|improve this answer



















        • 1




          one of the rare cases where one cares about the return value of addAll. indeed very clever, efficient and readable! ;-).
          – Aomine
          11 mins ago








        • 1




          Agreed. I believe it can't get simpler or more readable than this.
          – ernest_k
          10 mins ago
















        4














        You could try to check the return value of addAll. It will return true whenever the list has been modified, so try this:



        List<Object> list = new ArrayList<>();
        // ret unused, otherwise it doesn't compile
        boolean ret = list.addAll(method1())
        || list.addAll(method2())
        || list.addAll(method3())
        || list.addAll(method4())
        || list.addAll(method5())
        || list.addAll(method6());
        return list;


        Because of lazy evaluation, the first addAll operation that added at least one element will prevent the rest from bein called. I like the fact that "||" expresses the intent quite well.






        share|improve this answer



















        • 1




          one of the rare cases where one cares about the return value of addAll. indeed very clever, efficient and readable! ;-).
          – Aomine
          11 mins ago








        • 1




          Agreed. I believe it can't get simpler or more readable than this.
          – ernest_k
          10 mins ago














        4












        4








        4






        You could try to check the return value of addAll. It will return true whenever the list has been modified, so try this:



        List<Object> list = new ArrayList<>();
        // ret unused, otherwise it doesn't compile
        boolean ret = list.addAll(method1())
        || list.addAll(method2())
        || list.addAll(method3())
        || list.addAll(method4())
        || list.addAll(method5())
        || list.addAll(method6());
        return list;


        Because of lazy evaluation, the first addAll operation that added at least one element will prevent the rest from bein called. I like the fact that "||" expresses the intent quite well.






        share|improve this answer














        You could try to check the return value of addAll. It will return true whenever the list has been modified, so try this:



        List<Object> list = new ArrayList<>();
        // ret unused, otherwise it doesn't compile
        boolean ret = list.addAll(method1())
        || list.addAll(method2())
        || list.addAll(method3())
        || list.addAll(method4())
        || list.addAll(method5())
        || list.addAll(method6());
        return list;


        Because of lazy evaluation, the first addAll operation that added at least one element will prevent the rest from bein called. I like the fact that "||" expresses the intent quite well.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 24 mins ago

























        answered 31 mins ago









        Dorian Gray

        815313




        815313








        • 1




          one of the rare cases where one cares about the return value of addAll. indeed very clever, efficient and readable! ;-).
          – Aomine
          11 mins ago








        • 1




          Agreed. I believe it can't get simpler or more readable than this.
          – ernest_k
          10 mins ago














        • 1




          one of the rare cases where one cares about the return value of addAll. indeed very clever, efficient and readable! ;-).
          – Aomine
          11 mins ago








        • 1




          Agreed. I believe it can't get simpler or more readable than this.
          – ernest_k
          10 mins ago








        1




        1




        one of the rare cases where one cares about the return value of addAll. indeed very clever, efficient and readable! ;-).
        – Aomine
        11 mins ago






        one of the rare cases where one cares about the return value of addAll. indeed very clever, efficient and readable! ;-).
        – Aomine
        11 mins ago






        1




        1




        Agreed. I believe it can't get simpler or more readable than this.
        – ernest_k
        10 mins ago




        Agreed. I believe it can't get simpler or more readable than this.
        – ernest_k
        10 mins ago











        1














        A way of doing it without repeating yourself is to extract a method doing it for you:



        private void addIfEmpty(List<Object> targetList, Supplier<Collection<?>> supplier) {
        if (targetList.isEmpty()) {
        targetList.addAll(supplier.get());
        }
        }


        And then



        List<Object> list = new ArrayList<>();
        addIfEmpty(list, this::method1);
        addIfEmpty(list, this::method2);
        addIfEmpty(list, this::method3);
        addIfEmpty(list, this::method4);
        addIfEmpty(list, this::method5);
        addIfEmpty(list, this::method6);
        return list;


        Or even use a for loop:



        List<Supplier<Collection<?>>> suppliers = Arrays.asList(this::method1, this::method2, ...);
        List<Object> list = new ArrayList<>();
        suppliers.forEach(supplier -> this.addIfEmpty(list, supplier));


        Now DRY is not the most important aspect. If you think your original code is easier to read and understand, then keep it like that.






        share|improve this answer























        • You should rather name the method addIfEmpty instead of addIfNotEmpty
          – Ricola
          35 mins ago










        • @Ricola good point, indeed.
          – JB Nizet
          23 mins ago
















        1














        A way of doing it without repeating yourself is to extract a method doing it for you:



        private void addIfEmpty(List<Object> targetList, Supplier<Collection<?>> supplier) {
        if (targetList.isEmpty()) {
        targetList.addAll(supplier.get());
        }
        }


        And then



        List<Object> list = new ArrayList<>();
        addIfEmpty(list, this::method1);
        addIfEmpty(list, this::method2);
        addIfEmpty(list, this::method3);
        addIfEmpty(list, this::method4);
        addIfEmpty(list, this::method5);
        addIfEmpty(list, this::method6);
        return list;


        Or even use a for loop:



        List<Supplier<Collection<?>>> suppliers = Arrays.asList(this::method1, this::method2, ...);
        List<Object> list = new ArrayList<>();
        suppliers.forEach(supplier -> this.addIfEmpty(list, supplier));


        Now DRY is not the most important aspect. If you think your original code is easier to read and understand, then keep it like that.






        share|improve this answer























        • You should rather name the method addIfEmpty instead of addIfNotEmpty
          – Ricola
          35 mins ago










        • @Ricola good point, indeed.
          – JB Nizet
          23 mins ago














        1












        1








        1






        A way of doing it without repeating yourself is to extract a method doing it for you:



        private void addIfEmpty(List<Object> targetList, Supplier<Collection<?>> supplier) {
        if (targetList.isEmpty()) {
        targetList.addAll(supplier.get());
        }
        }


        And then



        List<Object> list = new ArrayList<>();
        addIfEmpty(list, this::method1);
        addIfEmpty(list, this::method2);
        addIfEmpty(list, this::method3);
        addIfEmpty(list, this::method4);
        addIfEmpty(list, this::method5);
        addIfEmpty(list, this::method6);
        return list;


        Or even use a for loop:



        List<Supplier<Collection<?>>> suppliers = Arrays.asList(this::method1, this::method2, ...);
        List<Object> list = new ArrayList<>();
        suppliers.forEach(supplier -> this.addIfEmpty(list, supplier));


        Now DRY is not the most important aspect. If you think your original code is easier to read and understand, then keep it like that.






        share|improve this answer














        A way of doing it without repeating yourself is to extract a method doing it for you:



        private void addIfEmpty(List<Object> targetList, Supplier<Collection<?>> supplier) {
        if (targetList.isEmpty()) {
        targetList.addAll(supplier.get());
        }
        }


        And then



        List<Object> list = new ArrayList<>();
        addIfEmpty(list, this::method1);
        addIfEmpty(list, this::method2);
        addIfEmpty(list, this::method3);
        addIfEmpty(list, this::method4);
        addIfEmpty(list, this::method5);
        addIfEmpty(list, this::method6);
        return list;


        Or even use a for loop:



        List<Supplier<Collection<?>>> suppliers = Arrays.asList(this::method1, this::method2, ...);
        List<Object> list = new ArrayList<>();
        suppliers.forEach(supplier -> this.addIfEmpty(list, supplier));


        Now DRY is not the most important aspect. If you think your original code is easier to read and understand, then keep it like that.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 24 mins ago

























        answered 1 hour ago









        JB Nizet

        534k51860993




        534k51860993












        • You should rather name the method addIfEmpty instead of addIfNotEmpty
          – Ricola
          35 mins ago










        • @Ricola good point, indeed.
          – JB Nizet
          23 mins ago


















        • You should rather name the method addIfEmpty instead of addIfNotEmpty
          – Ricola
          35 mins ago










        • @Ricola good point, indeed.
          – JB Nizet
          23 mins ago
















        You should rather name the method addIfEmpty instead of addIfNotEmpty
        – Ricola
        35 mins ago




        You should rather name the method addIfEmpty instead of addIfNotEmpty
        – Ricola
        35 mins ago












        @Ricola good point, indeed.
        – JB Nizet
        23 mins ago




        @Ricola good point, indeed.
        – JB Nizet
        23 mins ago











        1














        You could create a method as such:



        public static List<Object> lazyVersion(Supplier<List<Object>>... suppliers){
        return Arrays.stream(suppliers)
        .map(Supplier::get)
        .filter(s -> !s.isEmpty()) // or .filter(Predicate.not(List::isEmpty)) as of JDK11
        .findFirst()
        .orElseGet(Collections::emptyList);
        }


        and then call it as follows:



        lazyVersion(() -> method1(),
        () -> method2(),
        () -> method3(),
        () -> method4(),
        () -> method5(),
        () -> method6());


        method name for illustration purposes only.






        share|improve this answer




























          1














          You could create a method as such:



          public static List<Object> lazyVersion(Supplier<List<Object>>... suppliers){
          return Arrays.stream(suppliers)
          .map(Supplier::get)
          .filter(s -> !s.isEmpty()) // or .filter(Predicate.not(List::isEmpty)) as of JDK11
          .findFirst()
          .orElseGet(Collections::emptyList);
          }


          and then call it as follows:



          lazyVersion(() -> method1(),
          () -> method2(),
          () -> method3(),
          () -> method4(),
          () -> method5(),
          () -> method6());


          method name for illustration purposes only.






          share|improve this answer


























            1












            1








            1






            You could create a method as such:



            public static List<Object> lazyVersion(Supplier<List<Object>>... suppliers){
            return Arrays.stream(suppliers)
            .map(Supplier::get)
            .filter(s -> !s.isEmpty()) // or .filter(Predicate.not(List::isEmpty)) as of JDK11
            .findFirst()
            .orElseGet(Collections::emptyList);
            }


            and then call it as follows:



            lazyVersion(() -> method1(),
            () -> method2(),
            () -> method3(),
            () -> method4(),
            () -> method5(),
            () -> method6());


            method name for illustration purposes only.






            share|improve this answer














            You could create a method as such:



            public static List<Object> lazyVersion(Supplier<List<Object>>... suppliers){
            return Arrays.stream(suppliers)
            .map(Supplier::get)
            .filter(s -> !s.isEmpty()) // or .filter(Predicate.not(List::isEmpty)) as of JDK11
            .findFirst()
            .orElseGet(Collections::emptyList);
            }


            and then call it as follows:



            lazyVersion(() -> method1(),
            () -> method2(),
            () -> method3(),
            () -> method4(),
            () -> method5(),
            () -> method6());


            method name for illustration purposes only.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited 18 mins ago

























            answered 32 mins ago









            Aomine

            39.2k73669




            39.2k73669























                1














                You could make your code nicer by creating the method



                public void addAllIfEmpty(List<Object> list, Supplier<List<Object>> method){
                if(list.isEmpty()){
                list.addAll(method.get());
                }
                }


                Then you can use it like this (I assumed your methods are not static methods, if they are you need to reference them using ClassName::method1)



                List<Object> list = new ArrayList<>();
                list.addAll(method1());
                addAllIfEmpty(list, this::method2);
                addAllIfEmpty(list, this::method3);
                addAllIfEmpty(list, this::method4);
                addAllIfEmpty(list, this::method5);
                addAllIfEmpty(list, this::method6);
                return list;




                If you really want to use a Stream, you could do this



                 Stream.<Supplier<List<Object>>>of(this::method1, this::method2, this::method3, this::method4, this::method5, this::method6)
                .collect(ArrayList::new, this::addAllIfEmpty, ArrayList::addAll);


                IMO it makes it more complicated, depending on how your methods are referenced, it might be better to use a loop






                share|improve this answer




























                  1














                  You could make your code nicer by creating the method



                  public void addAllIfEmpty(List<Object> list, Supplier<List<Object>> method){
                  if(list.isEmpty()){
                  list.addAll(method.get());
                  }
                  }


                  Then you can use it like this (I assumed your methods are not static methods, if they are you need to reference them using ClassName::method1)



                  List<Object> list = new ArrayList<>();
                  list.addAll(method1());
                  addAllIfEmpty(list, this::method2);
                  addAllIfEmpty(list, this::method3);
                  addAllIfEmpty(list, this::method4);
                  addAllIfEmpty(list, this::method5);
                  addAllIfEmpty(list, this::method6);
                  return list;




                  If you really want to use a Stream, you could do this



                   Stream.<Supplier<List<Object>>>of(this::method1, this::method2, this::method3, this::method4, this::method5, this::method6)
                  .collect(ArrayList::new, this::addAllIfEmpty, ArrayList::addAll);


                  IMO it makes it more complicated, depending on how your methods are referenced, it might be better to use a loop






                  share|improve this answer


























                    1












                    1








                    1






                    You could make your code nicer by creating the method



                    public void addAllIfEmpty(List<Object> list, Supplier<List<Object>> method){
                    if(list.isEmpty()){
                    list.addAll(method.get());
                    }
                    }


                    Then you can use it like this (I assumed your methods are not static methods, if they are you need to reference them using ClassName::method1)



                    List<Object> list = new ArrayList<>();
                    list.addAll(method1());
                    addAllIfEmpty(list, this::method2);
                    addAllIfEmpty(list, this::method3);
                    addAllIfEmpty(list, this::method4);
                    addAllIfEmpty(list, this::method5);
                    addAllIfEmpty(list, this::method6);
                    return list;




                    If you really want to use a Stream, you could do this



                     Stream.<Supplier<List<Object>>>of(this::method1, this::method2, this::method3, this::method4, this::method5, this::method6)
                    .collect(ArrayList::new, this::addAllIfEmpty, ArrayList::addAll);


                    IMO it makes it more complicated, depending on how your methods are referenced, it might be better to use a loop






                    share|improve this answer














                    You could make your code nicer by creating the method



                    public void addAllIfEmpty(List<Object> list, Supplier<List<Object>> method){
                    if(list.isEmpty()){
                    list.addAll(method.get());
                    }
                    }


                    Then you can use it like this (I assumed your methods are not static methods, if they are you need to reference them using ClassName::method1)



                    List<Object> list = new ArrayList<>();
                    list.addAll(method1());
                    addAllIfEmpty(list, this::method2);
                    addAllIfEmpty(list, this::method3);
                    addAllIfEmpty(list, this::method4);
                    addAllIfEmpty(list, this::method5);
                    addAllIfEmpty(list, this::method6);
                    return list;




                    If you really want to use a Stream, you could do this



                     Stream.<Supplier<List<Object>>>of(this::method1, this::method2, this::method3, this::method4, this::method5, this::method6)
                    .collect(ArrayList::new, this::addAllIfEmpty, ArrayList::addAll);


                    IMO it makes it more complicated, depending on how your methods are referenced, it might be better to use a loop







                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited 10 mins ago

























                    answered 57 mins ago









                    Ricola

                    16510




                    16510























                        0














                        Java 8 streams weren't designed to support this kind of operation. From the jdk:



                        A stream should be operated on (invoking an intermediate or terminal stream operation) only once. This rules out, for example, "forked" streams, where the same source feeds two or more pipelines, or multiple traversals of the same stream.



                        If you can store it in memory you can use Collectors.partitioningBy if you have just two types and go by with a Map<Boolean, List>. Otherwise use Collectors.groupingBy.






                        share|improve this answer


























                          0














                          Java 8 streams weren't designed to support this kind of operation. From the jdk:



                          A stream should be operated on (invoking an intermediate or terminal stream operation) only once. This rules out, for example, "forked" streams, where the same source feeds two or more pipelines, or multiple traversals of the same stream.



                          If you can store it in memory you can use Collectors.partitioningBy if you have just two types and go by with a Map<Boolean, List>. Otherwise use Collectors.groupingBy.






                          share|improve this answer
























                            0












                            0








                            0






                            Java 8 streams weren't designed to support this kind of operation. From the jdk:



                            A stream should be operated on (invoking an intermediate or terminal stream operation) only once. This rules out, for example, "forked" streams, where the same source feeds two or more pipelines, or multiple traversals of the same stream.



                            If you can store it in memory you can use Collectors.partitioningBy if you have just two types and go by with a Map<Boolean, List>. Otherwise use Collectors.groupingBy.






                            share|improve this answer












                            Java 8 streams weren't designed to support this kind of operation. From the jdk:



                            A stream should be operated on (invoking an intermediate or terminal stream operation) only once. This rules out, for example, "forked" streams, where the same source feeds two or more pipelines, or multiple traversals of the same stream.



                            If you can store it in memory you can use Collectors.partitioningBy if you have just two types and go by with a Map<Boolean, List>. Otherwise use Collectors.groupingBy.







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered 1 hour ago









                            Sagar P. Ghagare

                            5218




                            5218






























                                draft saved

                                draft discarded




















































                                Thanks for contributing an answer to Stack Overflow!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.





                                Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                                Please pay close attention to the following guidance:


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53957780%2fjava-8-list-processing-add-elements-conditionally%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                Accessing regular linux commands in Huawei's Dopra Linux

                                Can't connect RFCOMM socket: Host is down

                                Kernel panic - not syncing: Fatal Exception in Interrupt