Java 8 list processing - add elements conditionally












28














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
    Dec 29 '18 at 8:47
















28














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
    Dec 29 '18 at 8:47














28












28








28


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 Dec 28 '18 at 12:42









Aomine

39.7k73770




39.7k73770










asked Dec 28 '18 at 11:24









ionut

17017




17017












  • What do the methods return as object, exactly?
    – Eric Duminil
    Dec 29 '18 at 8:47


















  • What do the methods return as object, exactly?
    – Eric Duminil
    Dec 29 '18 at 8:47
















What do the methods return as object, exactly?
– Eric Duminil
Dec 29 '18 at 8:47




What do the methods return as object, exactly?
– Eric Duminil
Dec 29 '18 at 8:47












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
    Dec 28 '18 at 12:01










  • 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
    Dec 28 '18 at 12:13






  • 5




    You can also use this::method1 to reduce ther amount of boilerplate
    – Boris the Spider
    Dec 28 '18 at 13:19






  • 1




    @BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
    – ernest_k
    Dec 28 '18 at 13:21






  • 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
    Dec 28 '18 at 20:07



















50














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
    Dec 28 '18 at 12:30








  • 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
    Dec 28 '18 at 13:24








  • 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
    Dec 28 '18 at 13:51








  • 10




    @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
    Dec 28 '18 at 16:01






  • 4




    this is the only solution here I would go with, an extremely rare case where addAll result actually matters. beautifully done, sir!
    – Eugene
    Dec 28 '18 at 22:14



















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
    Dec 28 '18 at 12:06










  • @Ricola good point, indeed.
    – JB Nizet
    Dec 28 '18 at 12:17



















5














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 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
        Dec 28 '18 at 12:01










      • 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
        Dec 28 '18 at 12:13






      • 5




        You can also use this::method1 to reduce ther amount of boilerplate
        – Boris the Spider
        Dec 28 '18 at 13:19






      • 1




        @BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
        – ernest_k
        Dec 28 '18 at 13:21






      • 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
        Dec 28 '18 at 20:07
















      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
        Dec 28 '18 at 12:01










      • 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
        Dec 28 '18 at 12:13






      • 5




        You can also use this::method1 to reduce ther amount of boilerplate
        – Boris the Spider
        Dec 28 '18 at 13:19






      • 1




        @BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
        – ernest_k
        Dec 28 '18 at 13:21






      • 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
        Dec 28 '18 at 20:07














      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 Dec 28 '18 at 12:19









      Aomine

      39.7k73770




      39.7k73770










      answered Dec 28 '18 at 11:44









      ernest_k

      20k42043




      20k42043








      • 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
        Dec 28 '18 at 12:01










      • 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
        Dec 28 '18 at 12:13






      • 5




        You can also use this::method1 to reduce ther amount of boilerplate
        – Boris the Spider
        Dec 28 '18 at 13:19






      • 1




        @BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
        – ernest_k
        Dec 28 '18 at 13:21






      • 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
        Dec 28 '18 at 20:07














      • 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
        Dec 28 '18 at 12:01










      • 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
        Dec 28 '18 at 12:13






      • 5




        You can also use this::method1 to reduce ther amount of boilerplate
        – Boris the Spider
        Dec 28 '18 at 13:19






      • 1




        @BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
        – ernest_k
        Dec 28 '18 at 13:21






      • 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
        Dec 28 '18 at 20:07








      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
      Dec 28 '18 at 12:01




      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
      Dec 28 '18 at 12:01












      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
      Dec 28 '18 at 12:13




      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
      Dec 28 '18 at 12:13




      5




      5




      You can also use this::method1 to reduce ther amount of boilerplate
      – Boris the Spider
      Dec 28 '18 at 13:19




      You can also use this::method1 to reduce ther amount of boilerplate
      – Boris the Spider
      Dec 28 '18 at 13:19




      1




      1




      @BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
      – ernest_k
      Dec 28 '18 at 13:21




      @BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
      – ernest_k
      Dec 28 '18 at 13:21




      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
      Dec 28 '18 at 20:07




      @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
      Dec 28 '18 at 20:07













      50














      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
        Dec 28 '18 at 12:30








      • 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
        Dec 28 '18 at 13:24








      • 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
        Dec 28 '18 at 13:51








      • 10




        @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
        Dec 28 '18 at 16:01






      • 4




        this is the only solution here I would go with, an extremely rare case where addAll result actually matters. beautifully done, sir!
        – Eugene
        Dec 28 '18 at 22:14
















      50














      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
        Dec 28 '18 at 12:30








      • 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
        Dec 28 '18 at 13:24








      • 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
        Dec 28 '18 at 13:51








      • 10




        @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
        Dec 28 '18 at 16:01






      • 4




        this is the only solution here I would go with, an extremely rare case where addAll result actually matters. beautifully done, sir!
        – Eugene
        Dec 28 '18 at 22:14














      50












      50








      50






      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 Dec 28 '18 at 12:17

























      answered Dec 28 '18 at 12:10









      Dorian Gray

      1,225415




      1,225415








      • 4




        one of the rare cases where one cares about the return value of addAll. indeed very clever, efficient and readable! ;-).
        – Aomine
        Dec 28 '18 at 12:30








      • 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
        Dec 28 '18 at 13:24








      • 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
        Dec 28 '18 at 13:51








      • 10




        @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
        Dec 28 '18 at 16:01






      • 4




        this is the only solution here I would go with, an extremely rare case where addAll result actually matters. beautifully done, sir!
        – Eugene
        Dec 28 '18 at 22:14














      • 4




        one of the rare cases where one cares about the return value of addAll. indeed very clever, efficient and readable! ;-).
        – Aomine
        Dec 28 '18 at 12:30








      • 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
        Dec 28 '18 at 13:24








      • 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
        Dec 28 '18 at 13:51








      • 10




        @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
        Dec 28 '18 at 16:01






      • 4




        this is the only solution here I would go with, an extremely rare case where addAll result actually matters. beautifully done, sir!
        – Eugene
        Dec 28 '18 at 22:14








      4




      4




      one of the rare cases where one cares about the return value of addAll. indeed very clever, efficient and readable! ;-).
      – Aomine
      Dec 28 '18 at 12:30






      one of the rare cases where one cares about the return value of addAll. indeed very clever, efficient and readable! ;-).
      – Aomine
      Dec 28 '18 at 12:30






      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
      Dec 28 '18 at 13:24






      @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
      Dec 28 '18 at 13:24






      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
      Dec 28 '18 at 13:51






      @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
      Dec 28 '18 at 13:51






      10




      10




      @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
      Dec 28 '18 at 16:01




      @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
      Dec 28 '18 at 16:01




      4




      4




      this is the only solution here I would go with, an extremely rare case where addAll result actually matters. beautifully done, sir!
      – Eugene
      Dec 28 '18 at 22:14




      this is the only solution here I would go with, an extremely rare case where addAll result actually matters. beautifully done, sir!
      – Eugene
      Dec 28 '18 at 22:14











      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
        Dec 28 '18 at 12:06










      • @Ricola good point, indeed.
        – JB Nizet
        Dec 28 '18 at 12:17
















      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
        Dec 28 '18 at 12:06










      • @Ricola good point, indeed.
        – JB Nizet
        Dec 28 '18 at 12:17














      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 Dec 28 '18 at 12:17

























      answered Dec 28 '18 at 11:38









      JB Nizet

      534k52860994




      534k52860994












      • You should rather name the method addIfEmpty instead of addIfNotEmpty
        – Ricola
        Dec 28 '18 at 12:06










      • @Ricola good point, indeed.
        – JB Nizet
        Dec 28 '18 at 12:17


















      • You should rather name the method addIfEmpty instead of addIfNotEmpty
        – Ricola
        Dec 28 '18 at 12:06










      • @Ricola good point, indeed.
        – JB Nizet
        Dec 28 '18 at 12:17
















      You should rather name the method addIfEmpty instead of addIfNotEmpty
      – Ricola
      Dec 28 '18 at 12:06




      You should rather name the method addIfEmpty instead of addIfNotEmpty
      – Ricola
      Dec 28 '18 at 12:06












      @Ricola good point, indeed.
      – JB Nizet
      Dec 28 '18 at 12:17




      @Ricola good point, indeed.
      – JB Nizet
      Dec 28 '18 at 12:17











      5














      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




























        5














        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


























          5












          5








          5






          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 Dec 28 '18 at 12:23

























          answered Dec 28 '18 at 12:08









          Aomine

          39.7k73770




          39.7k73770























              4














              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




























                4














                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


























                  4












                  4








                  4






                  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 Dec 28 '18 at 12:30

























                  answered Dec 28 '18 at 11:44









                  Ricola

                  442111




                  442111






























                      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

                      Human spaceflight

                      Can not write log (Is /dev/pts mounted?) - openpty in Ubuntu-on-Windows?

                      File:DeusFollowingSea.jpg