Java 8 list processing - add elements conditionally












29














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
























  • What do the methods return as object, exactly?
    – Eric Duminil
    yesterday
















29














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
























  • What do the methods return as object, exactly?
    – Eric Duminil
    yesterday














29












29








29


6





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 java-stream






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 2 days ago









Aomine

39.4k73669




39.4k73669










asked 2 days ago









ionut

17517




17517












  • What do the methods return as object, exactly?
    – Eric Duminil
    yesterday


















  • What do the methods return as object, exactly?
    – Eric Duminil
    yesterday
















What do the methods return as object, exactly?
– Eric Duminil
yesterday




What do the methods return as object, exactly?
– Eric Duminil
yesterday












5 Answers
5






active

oldest

votes


















29














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



















  • 5




    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
    2 days 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
    2 days ago






  • 4




    You can also use this::method1 to reduce ther amount of boilerplate
    – Boris the Spider
    2 days ago






  • 1




    @BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
    – ernest_k
    2 days ago






  • 3




    @SebastiaanvandenBroek certainly a matter of taste - I can't agree with your assessment. The code in the question has the same logic copy/pasted 5 times. The code above has no such repetition - to me this makes the functional logic rather superior.
    – Boris the Spider
    2 days ago



















48














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



















  • 4




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








  • 4




    @Aomine I don't find the misuse of boolean expressions to mimic ordered executions readable and maintainable at all. The next best bloke might reorder the expressions because "it's an OR expression, the order shouldn't matter" and boom you have a hard to find bug. The necessary comment about having a variable just for it to compile imho is a hint of bad design as well. So while this answers the question somehow, I wouldn't recommend to use this in production code.
    – Darkwing
    2 days ago








  • 3




    @DorianGray The methods hopefully won't be named method1...method6 in the code! That says nothing about what they do. And yes pragmatically there is a difference in the order, but logically it does not matter. This is why you should be really careful when assuming the execution order just because you know how your compiler/jvm will translate/execute the expression. If you are optimising down to the last bit, sure order it the way it makes most sense, but don't have business logic rely on it unless there is a really big benefit/demand to do so.
    – Darkwing
    2 days ago






  • 5




    @Darkwing It's not compiler/jvm specific behaviour, language specification itsself defines that behaviour of lazy evaluation. I'm not assuming anything, I know how the language is defined. The behaviour is widely known, e.g. lazy evaluation used in order to place a null check in the first place, dereferencing it afterwards. At least you have a very strange definition of assuming something that is defined in the language specification. The word assuming implies a certain uncertainity about the actual behaviour. If you know for sure what you are doing, you don't assume it.
    – Dorian Gray
    2 days ago








  • 9




    @Darkwing but... the order of OR does matter! A logical OR is a short-circuit operation and is used extensively exactly because of that.
    – Sebastiaan van den Broek
    2 days ago



















12














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
    2 days ago










  • @Ricola good point, indeed.
    – JB Nizet
    2 days ago



















4














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































    3














    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























      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

























      5 Answers
      5






      active

      oldest

      votes








      5 Answers
      5






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      29














      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



















      • 5




        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
        2 days 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
        2 days ago






      • 4




        You can also use this::method1 to reduce ther amount of boilerplate
        – Boris the Spider
        2 days ago






      • 1




        @BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
        – ernest_k
        2 days ago






      • 3




        @SebastiaanvandenBroek certainly a matter of taste - I can't agree with your assessment. The code in the question has the same logic copy/pasted 5 times. The code above has no such repetition - to me this makes the functional logic rather superior.
        – Boris the Spider
        2 days ago
















      29














      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



















      • 5




        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
        2 days 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
        2 days ago






      • 4




        You can also use this::method1 to reduce ther amount of boilerplate
        – Boris the Spider
        2 days ago






      • 1




        @BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
        – ernest_k
        2 days ago






      • 3




        @SebastiaanvandenBroek certainly a matter of taste - I can't agree with your assessment. The code in the question has the same logic copy/pasted 5 times. The code above has no such repetition - to me this makes the functional logic rather superior.
        – Boris the Spider
        2 days ago














      29












      29








      29






      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 2 days ago









      Aomine

      39.4k73669




      39.4k73669










      answered 2 days ago









      ernest_k

      19.9k42043




      19.9k42043








      • 5




        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
        2 days 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
        2 days ago






      • 4




        You can also use this::method1 to reduce ther amount of boilerplate
        – Boris the Spider
        2 days ago






      • 1




        @BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
        – ernest_k
        2 days ago






      • 3




        @SebastiaanvandenBroek certainly a matter of taste - I can't agree with your assessment. The code in the question has the same logic copy/pasted 5 times. The code above has no such repetition - to me this makes the functional logic rather superior.
        – Boris the Spider
        2 days ago














      • 5




        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
        2 days 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
        2 days ago






      • 4




        You can also use this::method1 to reduce ther amount of boilerplate
        – Boris the Spider
        2 days ago






      • 1




        @BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
        – ernest_k
        2 days ago






      • 3




        @SebastiaanvandenBroek certainly a matter of taste - I can't agree with your assessment. The code in the question has the same logic copy/pasted 5 times. The code above has no such repetition - to me this makes the functional logic rather superior.
        – Boris the Spider
        2 days ago








      5




      5




      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
      2 days 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
      2 days 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
      2 days 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
      2 days ago




      4




      4




      You can also use this::method1 to reduce ther amount of boilerplate
      – Boris the Spider
      2 days ago




      You can also use this::method1 to reduce ther amount of boilerplate
      – Boris the Spider
      2 days ago




      1




      1




      @BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
      – ernest_k
      2 days ago




      @BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
      – ernest_k
      2 days ago




      3




      3




      @SebastiaanvandenBroek certainly a matter of taste - I can't agree with your assessment. The code in the question has the same logic copy/pasted 5 times. The code above has no such repetition - to me this makes the functional logic rather superior.
      – Boris the Spider
      2 days ago




      @SebastiaanvandenBroek certainly a matter of taste - I can't agree with your assessment. The code in the question has the same logic copy/pasted 5 times. The code above has no such repetition - to me this makes the functional logic rather superior.
      – Boris the Spider
      2 days ago













      48














      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



















      • 4




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








      • 4




        @Aomine I don't find the misuse of boolean expressions to mimic ordered executions readable and maintainable at all. The next best bloke might reorder the expressions because "it's an OR expression, the order shouldn't matter" and boom you have a hard to find bug. The necessary comment about having a variable just for it to compile imho is a hint of bad design as well. So while this answers the question somehow, I wouldn't recommend to use this in production code.
        – Darkwing
        2 days ago








      • 3




        @DorianGray The methods hopefully won't be named method1...method6 in the code! That says nothing about what they do. And yes pragmatically there is a difference in the order, but logically it does not matter. This is why you should be really careful when assuming the execution order just because you know how your compiler/jvm will translate/execute the expression. If you are optimising down to the last bit, sure order it the way it makes most sense, but don't have business logic rely on it unless there is a really big benefit/demand to do so.
        – Darkwing
        2 days ago






      • 5




        @Darkwing It's not compiler/jvm specific behaviour, language specification itsself defines that behaviour of lazy evaluation. I'm not assuming anything, I know how the language is defined. The behaviour is widely known, e.g. lazy evaluation used in order to place a null check in the first place, dereferencing it afterwards. At least you have a very strange definition of assuming something that is defined in the language specification. The word assuming implies a certain uncertainity about the actual behaviour. If you know for sure what you are doing, you don't assume it.
        – Dorian Gray
        2 days ago








      • 9




        @Darkwing but... the order of OR does matter! A logical OR is a short-circuit operation and is used extensively exactly because of that.
        – Sebastiaan van den Broek
        2 days ago
















      48














      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



















      • 4




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








      • 4




        @Aomine I don't find the misuse of boolean expressions to mimic ordered executions readable and maintainable at all. The next best bloke might reorder the expressions because "it's an OR expression, the order shouldn't matter" and boom you have a hard to find bug. The necessary comment about having a variable just for it to compile imho is a hint of bad design as well. So while this answers the question somehow, I wouldn't recommend to use this in production code.
        – Darkwing
        2 days ago








      • 3




        @DorianGray The methods hopefully won't be named method1...method6 in the code! That says nothing about what they do. And yes pragmatically there is a difference in the order, but logically it does not matter. This is why you should be really careful when assuming the execution order just because you know how your compiler/jvm will translate/execute the expression. If you are optimising down to the last bit, sure order it the way it makes most sense, but don't have business logic rely on it unless there is a really big benefit/demand to do so.
        – Darkwing
        2 days ago






      • 5




        @Darkwing It's not compiler/jvm specific behaviour, language specification itsself defines that behaviour of lazy evaluation. I'm not assuming anything, I know how the language is defined. The behaviour is widely known, e.g. lazy evaluation used in order to place a null check in the first place, dereferencing it afterwards. At least you have a very strange definition of assuming something that is defined in the language specification. The word assuming implies a certain uncertainity about the actual behaviour. If you know for sure what you are doing, you don't assume it.
        – Dorian Gray
        2 days ago








      • 9




        @Darkwing but... the order of OR does matter! A logical OR is a short-circuit operation and is used extensively exactly because of that.
        – Sebastiaan van den Broek
        2 days ago














      48












      48








      48






      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 2 days ago

























      answered 2 days ago









      Dorian Gray

      1,205415




      1,205415








      • 4




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








      • 4




        @Aomine I don't find the misuse of boolean expressions to mimic ordered executions readable and maintainable at all. The next best bloke might reorder the expressions because "it's an OR expression, the order shouldn't matter" and boom you have a hard to find bug. The necessary comment about having a variable just for it to compile imho is a hint of bad design as well. So while this answers the question somehow, I wouldn't recommend to use this in production code.
        – Darkwing
        2 days ago








      • 3




        @DorianGray The methods hopefully won't be named method1...method6 in the code! That says nothing about what they do. And yes pragmatically there is a difference in the order, but logically it does not matter. This is why you should be really careful when assuming the execution order just because you know how your compiler/jvm will translate/execute the expression. If you are optimising down to the last bit, sure order it the way it makes most sense, but don't have business logic rely on it unless there is a really big benefit/demand to do so.
        – Darkwing
        2 days ago






      • 5




        @Darkwing It's not compiler/jvm specific behaviour, language specification itsself defines that behaviour of lazy evaluation. I'm not assuming anything, I know how the language is defined. The behaviour is widely known, e.g. lazy evaluation used in order to place a null check in the first place, dereferencing it afterwards. At least you have a very strange definition of assuming something that is defined in the language specification. The word assuming implies a certain uncertainity about the actual behaviour. If you know for sure what you are doing, you don't assume it.
        – Dorian Gray
        2 days ago








      • 9




        @Darkwing but... the order of OR does matter! A logical OR is a short-circuit operation and is used extensively exactly because of that.
        – Sebastiaan van den Broek
        2 days ago














      • 4




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








      • 4




        @Aomine I don't find the misuse of boolean expressions to mimic ordered executions readable and maintainable at all. The next best bloke might reorder the expressions because "it's an OR expression, the order shouldn't matter" and boom you have a hard to find bug. The necessary comment about having a variable just for it to compile imho is a hint of bad design as well. So while this answers the question somehow, I wouldn't recommend to use this in production code.
        – Darkwing
        2 days ago








      • 3




        @DorianGray The methods hopefully won't be named method1...method6 in the code! That says nothing about what they do. And yes pragmatically there is a difference in the order, but logically it does not matter. This is why you should be really careful when assuming the execution order just because you know how your compiler/jvm will translate/execute the expression. If you are optimising down to the last bit, sure order it the way it makes most sense, but don't have business logic rely on it unless there is a really big benefit/demand to do so.
        – Darkwing
        2 days ago






      • 5




        @Darkwing It's not compiler/jvm specific behaviour, language specification itsself defines that behaviour of lazy evaluation. I'm not assuming anything, I know how the language is defined. The behaviour is widely known, e.g. lazy evaluation used in order to place a null check in the first place, dereferencing it afterwards. At least you have a very strange definition of assuming something that is defined in the language specification. The word assuming implies a certain uncertainity about the actual behaviour. If you know for sure what you are doing, you don't assume it.
        – Dorian Gray
        2 days ago








      • 9




        @Darkwing but... the order of OR does matter! A logical OR is a short-circuit operation and is used extensively exactly because of that.
        – Sebastiaan van den Broek
        2 days ago








      4




      4




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






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






      4




      4




      @Aomine I don't find the misuse of boolean expressions to mimic ordered executions readable and maintainable at all. The next best bloke might reorder the expressions because "it's an OR expression, the order shouldn't matter" and boom you have a hard to find bug. The necessary comment about having a variable just for it to compile imho is a hint of bad design as well. So while this answers the question somehow, I wouldn't recommend to use this in production code.
      – Darkwing
      2 days ago






      @Aomine I don't find the misuse of boolean expressions to mimic ordered executions readable and maintainable at all. The next best bloke might reorder the expressions because "it's an OR expression, the order shouldn't matter" and boom you have a hard to find bug. The necessary comment about having a variable just for it to compile imho is a hint of bad design as well. So while this answers the question somehow, I wouldn't recommend to use this in production code.
      – Darkwing
      2 days ago






      3




      3




      @DorianGray The methods hopefully won't be named method1...method6 in the code! That says nothing about what they do. And yes pragmatically there is a difference in the order, but logically it does not matter. This is why you should be really careful when assuming the execution order just because you know how your compiler/jvm will translate/execute the expression. If you are optimising down to the last bit, sure order it the way it makes most sense, but don't have business logic rely on it unless there is a really big benefit/demand to do so.
      – Darkwing
      2 days ago




      @DorianGray The methods hopefully won't be named method1...method6 in the code! That says nothing about what they do. And yes pragmatically there is a difference in the order, but logically it does not matter. This is why you should be really careful when assuming the execution order just because you know how your compiler/jvm will translate/execute the expression. If you are optimising down to the last bit, sure order it the way it makes most sense, but don't have business logic rely on it unless there is a really big benefit/demand to do so.
      – Darkwing
      2 days ago




      5




      5




      @Darkwing It's not compiler/jvm specific behaviour, language specification itsself defines that behaviour of lazy evaluation. I'm not assuming anything, I know how the language is defined. The behaviour is widely known, e.g. lazy evaluation used in order to place a null check in the first place, dereferencing it afterwards. At least you have a very strange definition of assuming something that is defined in the language specification. The word assuming implies a certain uncertainity about the actual behaviour. If you know for sure what you are doing, you don't assume it.
      – Dorian Gray
      2 days ago






      @Darkwing It's not compiler/jvm specific behaviour, language specification itsself defines that behaviour of lazy evaluation. I'm not assuming anything, I know how the language is defined. The behaviour is widely known, e.g. lazy evaluation used in order to place a null check in the first place, dereferencing it afterwards. At least you have a very strange definition of assuming something that is defined in the language specification. The word assuming implies a certain uncertainity about the actual behaviour. If you know for sure what you are doing, you don't assume it.
      – Dorian Gray
      2 days ago






      9




      9




      @Darkwing but... the order of OR does matter! A logical OR is a short-circuit operation and is used extensively exactly because of that.
      – Sebastiaan van den Broek
      2 days ago




      @Darkwing but... the order of OR does matter! A logical OR is a short-circuit operation and is used extensively exactly because of that.
      – Sebastiaan van den Broek
      2 days ago











      12














      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
        2 days ago










      • @Ricola good point, indeed.
        – JB Nizet
        2 days ago
















      12














      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
        2 days ago










      • @Ricola good point, indeed.
        – JB Nizet
        2 days ago














      12












      12








      12






      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 2 days ago

























      answered 2 days ago









      JB Nizet

      534k52860994




      534k52860994












      • You should rather name the method addIfEmpty instead of addIfNotEmpty
        – Ricola
        2 days ago










      • @Ricola good point, indeed.
        – JB Nizet
        2 days ago


















      • You should rather name the method addIfEmpty instead of addIfNotEmpty
        – Ricola
        2 days ago










      • @Ricola good point, indeed.
        – JB Nizet
        2 days ago
















      You should rather name the method addIfEmpty instead of addIfNotEmpty
      – Ricola
      2 days ago




      You should rather name the method addIfEmpty instead of addIfNotEmpty
      – Ricola
      2 days ago












      @Ricola good point, indeed.
      – JB Nizet
      2 days ago




      @Ricola good point, indeed.
      – JB Nizet
      2 days ago











      4














      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




























        4














        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


























          4












          4








          4






          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 2 days ago

























          answered 2 days ago









          Aomine

          39.4k73669




          39.4k73669























              3














              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




























                3














                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


























                  3












                  3








                  3






                  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 2 days ago

























                  answered 2 days ago









                  Ricola

                  400111




                  400111






























                      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

                      If I really need a card on my start hand, how many mulligans make sense? [duplicate]

                      Alcedinidae

                      Can an atomic nucleus contain both particles and antiparticles? [duplicate]