Java: Proper way of creating a list containing all not-in-intersect elements from two given lists based on a...












5















Given two Lists of Objects, I'd be able to tell which items are not in their intersect based on one of their attributes. Let's look at the following example:



I have a class Foo that has two attributes: boo and placeholder



class Foo {
private int boo;
private int placeholder = 1;

public Foo(int boo) {
this.boo = boo;
}

public int getBoo() {
return boo;
}
}


Now I am creating two Lists from that (let's say this is my input)



    List<Foo> list1 = new ArrayList<Foo>();
list1.add(new Foo(1));
list1.add(new Foo(2));
list1.add(new Foo(3));

List<Foo> list2 = new ArrayList<Foo>();
list2.add(new Foo(0));
list2.add(new Foo(1));
list2.add(new Foo(2));


And now I'd like to say which Items are in list1 and not in list2 or in list2 and not in list1 based on their attribute boo. So in the above example I want a List<Foo> notInIntersectList that contains one Foo(0) and one Foo(3).



    List<Foo> notInIntersectList = new ArrayList<Foo>();
list1.forEach(li1foo -> {
boolean inBothLists = false;
list2.forEach(li2foo -> {
if (li1foo.getBoo() == li2foo.getBoo()) {
inBothLists = true;
}
});
if (!inBothLists) {
notInIntersectList.add(li1foo);
}
});
//now I covered all items in list1 but not in list2. Now do this again with lists swapped, so I can also cover those.
//...


Sadly I am getting Local variable inBothLists defined in an enclosing scope must be final or effectively final as an error. How is this issue solved properly, since this seems not to be the "right" solution?










share|improve this question























  • Try with a traditional for loop, instead of overusing a lambda, and you should be fine. Code isn't better just because it has a lambda expression! list2.forEach(li2foo -> { is not more elegant than for(Foo li2foo : list2) {, and you lose the ability to break and modify local variables.

    – Anony-Mousse
    Jan 1 at 15:16


















5















Given two Lists of Objects, I'd be able to tell which items are not in their intersect based on one of their attributes. Let's look at the following example:



I have a class Foo that has two attributes: boo and placeholder



class Foo {
private int boo;
private int placeholder = 1;

public Foo(int boo) {
this.boo = boo;
}

public int getBoo() {
return boo;
}
}


Now I am creating two Lists from that (let's say this is my input)



    List<Foo> list1 = new ArrayList<Foo>();
list1.add(new Foo(1));
list1.add(new Foo(2));
list1.add(new Foo(3));

List<Foo> list2 = new ArrayList<Foo>();
list2.add(new Foo(0));
list2.add(new Foo(1));
list2.add(new Foo(2));


And now I'd like to say which Items are in list1 and not in list2 or in list2 and not in list1 based on their attribute boo. So in the above example I want a List<Foo> notInIntersectList that contains one Foo(0) and one Foo(3).



    List<Foo> notInIntersectList = new ArrayList<Foo>();
list1.forEach(li1foo -> {
boolean inBothLists = false;
list2.forEach(li2foo -> {
if (li1foo.getBoo() == li2foo.getBoo()) {
inBothLists = true;
}
});
if (!inBothLists) {
notInIntersectList.add(li1foo);
}
});
//now I covered all items in list1 but not in list2. Now do this again with lists swapped, so I can also cover those.
//...


Sadly I am getting Local variable inBothLists defined in an enclosing scope must be final or effectively final as an error. How is this issue solved properly, since this seems not to be the "right" solution?










share|improve this question























  • Try with a traditional for loop, instead of overusing a lambda, and you should be fine. Code isn't better just because it has a lambda expression! list2.forEach(li2foo -> { is not more elegant than for(Foo li2foo : list2) {, and you lose the ability to break and modify local variables.

    – Anony-Mousse
    Jan 1 at 15:16
















5












5








5


1






Given two Lists of Objects, I'd be able to tell which items are not in their intersect based on one of their attributes. Let's look at the following example:



I have a class Foo that has two attributes: boo and placeholder



class Foo {
private int boo;
private int placeholder = 1;

public Foo(int boo) {
this.boo = boo;
}

public int getBoo() {
return boo;
}
}


Now I am creating two Lists from that (let's say this is my input)



    List<Foo> list1 = new ArrayList<Foo>();
list1.add(new Foo(1));
list1.add(new Foo(2));
list1.add(new Foo(3));

List<Foo> list2 = new ArrayList<Foo>();
list2.add(new Foo(0));
list2.add(new Foo(1));
list2.add(new Foo(2));


And now I'd like to say which Items are in list1 and not in list2 or in list2 and not in list1 based on their attribute boo. So in the above example I want a List<Foo> notInIntersectList that contains one Foo(0) and one Foo(3).



    List<Foo> notInIntersectList = new ArrayList<Foo>();
list1.forEach(li1foo -> {
boolean inBothLists = false;
list2.forEach(li2foo -> {
if (li1foo.getBoo() == li2foo.getBoo()) {
inBothLists = true;
}
});
if (!inBothLists) {
notInIntersectList.add(li1foo);
}
});
//now I covered all items in list1 but not in list2. Now do this again with lists swapped, so I can also cover those.
//...


Sadly I am getting Local variable inBothLists defined in an enclosing scope must be final or effectively final as an error. How is this issue solved properly, since this seems not to be the "right" solution?










share|improve this question














Given two Lists of Objects, I'd be able to tell which items are not in their intersect based on one of their attributes. Let's look at the following example:



I have a class Foo that has two attributes: boo and placeholder



class Foo {
private int boo;
private int placeholder = 1;

public Foo(int boo) {
this.boo = boo;
}

public int getBoo() {
return boo;
}
}


Now I am creating two Lists from that (let's say this is my input)



    List<Foo> list1 = new ArrayList<Foo>();
list1.add(new Foo(1));
list1.add(new Foo(2));
list1.add(new Foo(3));

List<Foo> list2 = new ArrayList<Foo>();
list2.add(new Foo(0));
list2.add(new Foo(1));
list2.add(new Foo(2));


And now I'd like to say which Items are in list1 and not in list2 or in list2 and not in list1 based on their attribute boo. So in the above example I want a List<Foo> notInIntersectList that contains one Foo(0) and one Foo(3).



    List<Foo> notInIntersectList = new ArrayList<Foo>();
list1.forEach(li1foo -> {
boolean inBothLists = false;
list2.forEach(li2foo -> {
if (li1foo.getBoo() == li2foo.getBoo()) {
inBothLists = true;
}
});
if (!inBothLists) {
notInIntersectList.add(li1foo);
}
});
//now I covered all items in list1 but not in list2. Now do this again with lists swapped, so I can also cover those.
//...


Sadly I am getting Local variable inBothLists defined in an enclosing scope must be final or effectively final as an error. How is this issue solved properly, since this seems not to be the "right" solution?







java






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jan 1 at 14:04









RüdigerRüdiger

221323




221323













  • Try with a traditional for loop, instead of overusing a lambda, and you should be fine. Code isn't better just because it has a lambda expression! list2.forEach(li2foo -> { is not more elegant than for(Foo li2foo : list2) {, and you lose the ability to break and modify local variables.

    – Anony-Mousse
    Jan 1 at 15:16





















  • Try with a traditional for loop, instead of overusing a lambda, and you should be fine. Code isn't better just because it has a lambda expression! list2.forEach(li2foo -> { is not more elegant than for(Foo li2foo : list2) {, and you lose the ability to break and modify local variables.

    – Anony-Mousse
    Jan 1 at 15:16



















Try with a traditional for loop, instead of overusing a lambda, and you should be fine. Code isn't better just because it has a lambda expression! list2.forEach(li2foo -> { is not more elegant than for(Foo li2foo : list2) {, and you lose the ability to break and modify local variables.

– Anony-Mousse
Jan 1 at 15:16







Try with a traditional for loop, instead of overusing a lambda, and you should be fine. Code isn't better just because it has a lambda expression! list2.forEach(li2foo -> { is not more elegant than for(Foo li2foo : list2) {, and you lose the ability to break and modify local variables.

– Anony-Mousse
Jan 1 at 15:16














6 Answers
6






active

oldest

votes


















6














You cannot mutate variables inside a lambda expression (See: Variable used in lambda expression should be final or effectively final)



Here's a way to fix your code (fun with Streams)



List<Foo> notInIntersectList = list1.stream()
.filter(fooElementFromList1 -> list2
.stream()
.noneMatch(fooElementFromList2 -> fooElementFromList2.getBoo() == fooElementFromList1.getBoo()))
.collect(Collectors.toCollection(ArrayList::new));

list2.stream()
.filter(fooElementFromList2 -> list1
.stream()
.noneMatch(fooElementFromList1 -> fooElementFromList1.getBoo() == fooElementFromList2.getBoo()))
.forEach(notInIntersectList::add);


The complexity of this is O(n*m) (where n and m are the number of elements in list1 and list2 respectively).



To do this in O(n+m), you can use a Set. For this, you need a equals and hashcode method on the Foo class. This considers two Foo instances as equal only based on the value of the instance variable boo.



class Foo {
....

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Foo other = (Foo) obj;
return boo == other.boo;
}

@Override
public int hashCode() {
return boo;
}
}


And use a Set for this as



Set<Foo> fooSet1 = new HashSet<>(list1);
Set<Foo> fooSet2 = new HashSet<>(list2);

fooSet1.removeAll(list2);
fooSet2.removeAll(list1);

List<Foo> notInIntersectList = Stream.concat(fooSet1.stream(), fooSet2.stream())
.collect(Collectors.toList());





share|improve this answer


























  • Assuming I'd have a non-numeric value as attribute I'm comparing (e.g. a string) would I still need to override the hashCode()? So I see it makes sense to simply override the equals()-method, but why do I also need to override the hashCode?

    – Rüdiger
    Jan 1 at 14:38











  • See this - [Why do I need to override the equals and hashCode methods in Java? ](stackoverflow.com/questions/2265503/…)

    – user7
    Jan 1 at 14:39













  • If you put this object in a hashmap, then you can find it with the correct hashCode function. If you do not override it, it will be lost.

    – Charlie
    Jan 1 at 14:39



















3














If you cannot create an equals and hashCode on your class (maybe they have them already but not based on boo), what I would do is:




  • Create a Set<Integer> (or a BitSet) containing all the boo values in list 1. Call it set1

  • Create a Set<Integer> (or a BitSet) containing all the boo values in list 2. Call it set2

  • Use set1.retainAll(set2) to get the intersection of the two sets.


  • Use the following to create my list:



    Stream.concat(list1.stream(),list2.stream())
    .filter(item-> ! set1.contains(item.getBoo()))
    .collect(Collectors.toList);



This is O(m+n) and also ensures the order of the items in the original lists is maintained, as well as any duplicates (items having the same boo).






share|improve this answer































    3














    First of all, you shall add the methods equals and hashCode to your class Foo (see Why do I need to override the equals and hashCode methods in Java?)



    class Foo {
    private int boo;
    private int placeholder = 1;

    public Foo(int boo) {
    this.boo = boo;
    }

    public int getBoo() {
    return boo;
    }

    @Override
    public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + boo;
    return result;
    }

    @Override
    public boolean equals(Object obj) {
    if (this == obj)
    return true;
    if (obj == null)
    return false;
    if (!(obj instanceof Foo))
    return false;
    Foo other = (Foo) obj;
    return boo == other.boo;
    }

    }


    Now you can use the removeAll method of List:




    Removes all of this collection's elements that are also contained in
    the specified collection (optional operation). After this call
    returns, this collection will contain no elements in common with the
    specified collection.




    You will have to build a new List notInIntersectList like that:



        List<Foo> listIntersection = new ArrayList<>(list1);
    listIntersection.removeAll(list2);

    List<Foo> notInIntersectList = new ArrayList<>(list1);
    notInIntersectList.addAll(list2);
    notInIntersectList.removeAll(listIntersection);





    share|improve this answer


























    • It seems you are keeping the intersection rather than the items not in the intersection.

      – RealSkeptic
      Jan 1 at 14:32











    • Oh, sorry, that's true. I'll fix it, thanks!

      – Dorian Gray
      Jan 1 at 14:33



















    1














    avoid Lambda expressions



    They make code harder to read, and less efficient.



    If you simply use traditional for loops, your code should work... plus, you can use break to stop searching for a second match.



        List<Foo> notInIntersectList = new ArrayList<Foo>();
    for(Foo li1foo : list1) {
    boolean inBothLists = false;
    for(Foo li2foo : list2) {
    if (li1foo.getBoo() == li2foo.getBoo()) {
    inBothLists = true;
    }
    }
    if (!inBothLists) {
    notInIntersectList.add(li1foo);
    }
    }


    You probably still recognize your code there... Now here's the pro version with imperative coding:



        List<Foo> notInIntersectList = new ArrayList<Foo>();
    nextfoo: for(Foo li1foo : list1) {
    for(Foo li2foo : list2)
    if (li1foo.getBoo() == li2foo.getBoo())
    continue nextfoo;
    notInIntersectList.add(li1foo);
    }


    This actually has a very clear and explicit logic (and it will make functional fans puke because of the effective "goto"). It's still slow if list2 is huge though, I didn't want to change your algorithm.






    share|improve this answer































      0














      There is already a library for that:



      Set<String> wordsWithPrimeLength = ImmutableSet.of("one", "two", "three", "six", "seven", "eight");
      Set<String> primes = ImmutableSet.of("two", "three", "five", "seven");

      SetView<String> intersection = Sets.intersection(primes, wordsWithPrimeLength); // contains "two", "three", "seven"
      // I can use intersection as a Set directly, but copying it can be more efficient if I use it a lot.
      return intersection.immutableCopy();


      If you use difference(Set<E> set1, Set<?> set2) instead of intersection(Set<E> set1, Set<?> set2), you will get the difference of the two.



      With ImmutableSet.copyOf(Collection<? extends E> elements) you can create a Set.



      It is called Guava and provides many collection operations:
      https://github.com/google/guava/wiki/CollectionUtilitiesExplained



      The API: https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/ImmutableSet.html






      share|improve this answer


























      • Op wants to have the non-intersected values!

        – Seelenvirtuose
        Jan 1 at 14:40











      • I corrected my answer. Thanks.

        – Charlie
        Jan 1 at 14:45



















      0














      I see here four possible solutions:



      1) Avoid lambda expression following @Anony-Mousse's response



      2) Include the variable at the class level (not recommended because this boolean is meant for local use):



      public class Testing {
      boolean inBothLists = true;

      public static void main(String args) {
      List<Foo> notInIntersectList = new ArrayList<Foo>();
      list1.forEach(li1foo -> {
      inBothLists = false;
      list2.forEach(li2foo -> {
      if (li1foo.getBoo() == li2foo.getBoo()) {
      inBothLists = true;
      }
      });
      if (!inBothLists) {
      notInIntersectList.add(li1foo);
      }
      });

      System.out.println("Intersected values:");
      notInIntersectList.forEach(liInFoo -> {
      System.out.println(liInFoo);
      });

      }


      3) Using contains method from List (avoiding boolean):



      List<Foo> notInIntersectList = new ArrayList<Foo>();
      list1.forEach(li1foo -> {
      if (!list2.contains(li1foo))
      notInIntersectList.add(li1foo);
      });


      4) Java8 Stream API (already mentioned in another answer and avoiding boolean):



      List<Foo> notInIntersectList = new ArrayList<Foo>();
      list1.forEach(li1foo -> {
      Foo result = list2.stream()
      .filter(li2foo -> li1foo.getBoo() == li2foo.getBoo() )
      .findAny()
      .orElse(null);
      if (result == null)
      notInIntersectList.add(li1foo);
      });


      I would go for option 1), 3) or 4). I only kept 2.) to show an example using variables inside lambda functions.



      UPDATE: I found 3) and 4) options in a recent Baeldung post on how to find an Element in a List






      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%2f53996101%2fjava-proper-way-of-creating-a-list-containing-all-not-in-intersect-elements-fro%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        6 Answers
        6






        active

        oldest

        votes








        6 Answers
        6






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        6














        You cannot mutate variables inside a lambda expression (See: Variable used in lambda expression should be final or effectively final)



        Here's a way to fix your code (fun with Streams)



        List<Foo> notInIntersectList = list1.stream()
        .filter(fooElementFromList1 -> list2
        .stream()
        .noneMatch(fooElementFromList2 -> fooElementFromList2.getBoo() == fooElementFromList1.getBoo()))
        .collect(Collectors.toCollection(ArrayList::new));

        list2.stream()
        .filter(fooElementFromList2 -> list1
        .stream()
        .noneMatch(fooElementFromList1 -> fooElementFromList1.getBoo() == fooElementFromList2.getBoo()))
        .forEach(notInIntersectList::add);


        The complexity of this is O(n*m) (where n and m are the number of elements in list1 and list2 respectively).



        To do this in O(n+m), you can use a Set. For this, you need a equals and hashcode method on the Foo class. This considers two Foo instances as equal only based on the value of the instance variable boo.



        class Foo {
        ....

        @Override
        public boolean equals(Object obj) {
        if (this == obj)
        return true;
        if (obj == null)
        return false;
        if (getClass() != obj.getClass())
        return false;
        Foo other = (Foo) obj;
        return boo == other.boo;
        }

        @Override
        public int hashCode() {
        return boo;
        }
        }


        And use a Set for this as



        Set<Foo> fooSet1 = new HashSet<>(list1);
        Set<Foo> fooSet2 = new HashSet<>(list2);

        fooSet1.removeAll(list2);
        fooSet2.removeAll(list1);

        List<Foo> notInIntersectList = Stream.concat(fooSet1.stream(), fooSet2.stream())
        .collect(Collectors.toList());





        share|improve this answer


























        • Assuming I'd have a non-numeric value as attribute I'm comparing (e.g. a string) would I still need to override the hashCode()? So I see it makes sense to simply override the equals()-method, but why do I also need to override the hashCode?

          – Rüdiger
          Jan 1 at 14:38











        • See this - [Why do I need to override the equals and hashCode methods in Java? ](stackoverflow.com/questions/2265503/…)

          – user7
          Jan 1 at 14:39













        • If you put this object in a hashmap, then you can find it with the correct hashCode function. If you do not override it, it will be lost.

          – Charlie
          Jan 1 at 14:39
















        6














        You cannot mutate variables inside a lambda expression (See: Variable used in lambda expression should be final or effectively final)



        Here's a way to fix your code (fun with Streams)



        List<Foo> notInIntersectList = list1.stream()
        .filter(fooElementFromList1 -> list2
        .stream()
        .noneMatch(fooElementFromList2 -> fooElementFromList2.getBoo() == fooElementFromList1.getBoo()))
        .collect(Collectors.toCollection(ArrayList::new));

        list2.stream()
        .filter(fooElementFromList2 -> list1
        .stream()
        .noneMatch(fooElementFromList1 -> fooElementFromList1.getBoo() == fooElementFromList2.getBoo()))
        .forEach(notInIntersectList::add);


        The complexity of this is O(n*m) (where n and m are the number of elements in list1 and list2 respectively).



        To do this in O(n+m), you can use a Set. For this, you need a equals and hashcode method on the Foo class. This considers two Foo instances as equal only based on the value of the instance variable boo.



        class Foo {
        ....

        @Override
        public boolean equals(Object obj) {
        if (this == obj)
        return true;
        if (obj == null)
        return false;
        if (getClass() != obj.getClass())
        return false;
        Foo other = (Foo) obj;
        return boo == other.boo;
        }

        @Override
        public int hashCode() {
        return boo;
        }
        }


        And use a Set for this as



        Set<Foo> fooSet1 = new HashSet<>(list1);
        Set<Foo> fooSet2 = new HashSet<>(list2);

        fooSet1.removeAll(list2);
        fooSet2.removeAll(list1);

        List<Foo> notInIntersectList = Stream.concat(fooSet1.stream(), fooSet2.stream())
        .collect(Collectors.toList());





        share|improve this answer


























        • Assuming I'd have a non-numeric value as attribute I'm comparing (e.g. a string) would I still need to override the hashCode()? So I see it makes sense to simply override the equals()-method, but why do I also need to override the hashCode?

          – Rüdiger
          Jan 1 at 14:38











        • See this - [Why do I need to override the equals and hashCode methods in Java? ](stackoverflow.com/questions/2265503/…)

          – user7
          Jan 1 at 14:39













        • If you put this object in a hashmap, then you can find it with the correct hashCode function. If you do not override it, it will be lost.

          – Charlie
          Jan 1 at 14:39














        6












        6








        6







        You cannot mutate variables inside a lambda expression (See: Variable used in lambda expression should be final or effectively final)



        Here's a way to fix your code (fun with Streams)



        List<Foo> notInIntersectList = list1.stream()
        .filter(fooElementFromList1 -> list2
        .stream()
        .noneMatch(fooElementFromList2 -> fooElementFromList2.getBoo() == fooElementFromList1.getBoo()))
        .collect(Collectors.toCollection(ArrayList::new));

        list2.stream()
        .filter(fooElementFromList2 -> list1
        .stream()
        .noneMatch(fooElementFromList1 -> fooElementFromList1.getBoo() == fooElementFromList2.getBoo()))
        .forEach(notInIntersectList::add);


        The complexity of this is O(n*m) (where n and m are the number of elements in list1 and list2 respectively).



        To do this in O(n+m), you can use a Set. For this, you need a equals and hashcode method on the Foo class. This considers two Foo instances as equal only based on the value of the instance variable boo.



        class Foo {
        ....

        @Override
        public boolean equals(Object obj) {
        if (this == obj)
        return true;
        if (obj == null)
        return false;
        if (getClass() != obj.getClass())
        return false;
        Foo other = (Foo) obj;
        return boo == other.boo;
        }

        @Override
        public int hashCode() {
        return boo;
        }
        }


        And use a Set for this as



        Set<Foo> fooSet1 = new HashSet<>(list1);
        Set<Foo> fooSet2 = new HashSet<>(list2);

        fooSet1.removeAll(list2);
        fooSet2.removeAll(list1);

        List<Foo> notInIntersectList = Stream.concat(fooSet1.stream(), fooSet2.stream())
        .collect(Collectors.toList());





        share|improve this answer















        You cannot mutate variables inside a lambda expression (See: Variable used in lambda expression should be final or effectively final)



        Here's a way to fix your code (fun with Streams)



        List<Foo> notInIntersectList = list1.stream()
        .filter(fooElementFromList1 -> list2
        .stream()
        .noneMatch(fooElementFromList2 -> fooElementFromList2.getBoo() == fooElementFromList1.getBoo()))
        .collect(Collectors.toCollection(ArrayList::new));

        list2.stream()
        .filter(fooElementFromList2 -> list1
        .stream()
        .noneMatch(fooElementFromList1 -> fooElementFromList1.getBoo() == fooElementFromList2.getBoo()))
        .forEach(notInIntersectList::add);


        The complexity of this is O(n*m) (where n and m are the number of elements in list1 and list2 respectively).



        To do this in O(n+m), you can use a Set. For this, you need a equals and hashcode method on the Foo class. This considers two Foo instances as equal only based on the value of the instance variable boo.



        class Foo {
        ....

        @Override
        public boolean equals(Object obj) {
        if (this == obj)
        return true;
        if (obj == null)
        return false;
        if (getClass() != obj.getClass())
        return false;
        Foo other = (Foo) obj;
        return boo == other.boo;
        }

        @Override
        public int hashCode() {
        return boo;
        }
        }


        And use a Set for this as



        Set<Foo> fooSet1 = new HashSet<>(list1);
        Set<Foo> fooSet2 = new HashSet<>(list2);

        fooSet1.removeAll(list2);
        fooSet2.removeAll(list1);

        List<Foo> notInIntersectList = Stream.concat(fooSet1.stream(), fooSet2.stream())
        .collect(Collectors.toList());






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Jan 1 at 14:28

























        answered Jan 1 at 14:11









        user7user7

        9,62932446




        9,62932446













        • Assuming I'd have a non-numeric value as attribute I'm comparing (e.g. a string) would I still need to override the hashCode()? So I see it makes sense to simply override the equals()-method, but why do I also need to override the hashCode?

          – Rüdiger
          Jan 1 at 14:38











        • See this - [Why do I need to override the equals and hashCode methods in Java? ](stackoverflow.com/questions/2265503/…)

          – user7
          Jan 1 at 14:39













        • If you put this object in a hashmap, then you can find it with the correct hashCode function. If you do not override it, it will be lost.

          – Charlie
          Jan 1 at 14:39



















        • Assuming I'd have a non-numeric value as attribute I'm comparing (e.g. a string) would I still need to override the hashCode()? So I see it makes sense to simply override the equals()-method, but why do I also need to override the hashCode?

          – Rüdiger
          Jan 1 at 14:38











        • See this - [Why do I need to override the equals and hashCode methods in Java? ](stackoverflow.com/questions/2265503/…)

          – user7
          Jan 1 at 14:39













        • If you put this object in a hashmap, then you can find it with the correct hashCode function. If you do not override it, it will be lost.

          – Charlie
          Jan 1 at 14:39

















        Assuming I'd have a non-numeric value as attribute I'm comparing (e.g. a string) would I still need to override the hashCode()? So I see it makes sense to simply override the equals()-method, but why do I also need to override the hashCode?

        – Rüdiger
        Jan 1 at 14:38





        Assuming I'd have a non-numeric value as attribute I'm comparing (e.g. a string) would I still need to override the hashCode()? So I see it makes sense to simply override the equals()-method, but why do I also need to override the hashCode?

        – Rüdiger
        Jan 1 at 14:38













        See this - [Why do I need to override the equals and hashCode methods in Java? ](stackoverflow.com/questions/2265503/…)

        – user7
        Jan 1 at 14:39







        See this - [Why do I need to override the equals and hashCode methods in Java? ](stackoverflow.com/questions/2265503/…)

        – user7
        Jan 1 at 14:39















        If you put this object in a hashmap, then you can find it with the correct hashCode function. If you do not override it, it will be lost.

        – Charlie
        Jan 1 at 14:39





        If you put this object in a hashmap, then you can find it with the correct hashCode function. If you do not override it, it will be lost.

        – Charlie
        Jan 1 at 14:39













        3














        If you cannot create an equals and hashCode on your class (maybe they have them already but not based on boo), what I would do is:




        • Create a Set<Integer> (or a BitSet) containing all the boo values in list 1. Call it set1

        • Create a Set<Integer> (or a BitSet) containing all the boo values in list 2. Call it set2

        • Use set1.retainAll(set2) to get the intersection of the two sets.


        • Use the following to create my list:



          Stream.concat(list1.stream(),list2.stream())
          .filter(item-> ! set1.contains(item.getBoo()))
          .collect(Collectors.toList);



        This is O(m+n) and also ensures the order of the items in the original lists is maintained, as well as any duplicates (items having the same boo).






        share|improve this answer




























          3














          If you cannot create an equals and hashCode on your class (maybe they have them already but not based on boo), what I would do is:




          • Create a Set<Integer> (or a BitSet) containing all the boo values in list 1. Call it set1

          • Create a Set<Integer> (or a BitSet) containing all the boo values in list 2. Call it set2

          • Use set1.retainAll(set2) to get the intersection of the two sets.


          • Use the following to create my list:



            Stream.concat(list1.stream(),list2.stream())
            .filter(item-> ! set1.contains(item.getBoo()))
            .collect(Collectors.toList);



          This is O(m+n) and also ensures the order of the items in the original lists is maintained, as well as any duplicates (items having the same boo).






          share|improve this answer


























            3












            3








            3







            If you cannot create an equals and hashCode on your class (maybe they have them already but not based on boo), what I would do is:




            • Create a Set<Integer> (or a BitSet) containing all the boo values in list 1. Call it set1

            • Create a Set<Integer> (or a BitSet) containing all the boo values in list 2. Call it set2

            • Use set1.retainAll(set2) to get the intersection of the two sets.


            • Use the following to create my list:



              Stream.concat(list1.stream(),list2.stream())
              .filter(item-> ! set1.contains(item.getBoo()))
              .collect(Collectors.toList);



            This is O(m+n) and also ensures the order of the items in the original lists is maintained, as well as any duplicates (items having the same boo).






            share|improve this answer













            If you cannot create an equals and hashCode on your class (maybe they have them already but not based on boo), what I would do is:




            • Create a Set<Integer> (or a BitSet) containing all the boo values in list 1. Call it set1

            • Create a Set<Integer> (or a BitSet) containing all the boo values in list 2. Call it set2

            • Use set1.retainAll(set2) to get the intersection of the two sets.


            • Use the following to create my list:



              Stream.concat(list1.stream(),list2.stream())
              .filter(item-> ! set1.contains(item.getBoo()))
              .collect(Collectors.toList);



            This is O(m+n) and also ensures the order of the items in the original lists is maintained, as well as any duplicates (items having the same boo).







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Jan 1 at 14:27









            RealSkepticRealSkeptic

            28.2k63463




            28.2k63463























                3














                First of all, you shall add the methods equals and hashCode to your class Foo (see Why do I need to override the equals and hashCode methods in Java?)



                class Foo {
                private int boo;
                private int placeholder = 1;

                public Foo(int boo) {
                this.boo = boo;
                }

                public int getBoo() {
                return boo;
                }

                @Override
                public int hashCode() {
                final int prime = 31;
                int result = 1;
                result = prime * result + boo;
                return result;
                }

                @Override
                public boolean equals(Object obj) {
                if (this == obj)
                return true;
                if (obj == null)
                return false;
                if (!(obj instanceof Foo))
                return false;
                Foo other = (Foo) obj;
                return boo == other.boo;
                }

                }


                Now you can use the removeAll method of List:




                Removes all of this collection's elements that are also contained in
                the specified collection (optional operation). After this call
                returns, this collection will contain no elements in common with the
                specified collection.




                You will have to build a new List notInIntersectList like that:



                    List<Foo> listIntersection = new ArrayList<>(list1);
                listIntersection.removeAll(list2);

                List<Foo> notInIntersectList = new ArrayList<>(list1);
                notInIntersectList.addAll(list2);
                notInIntersectList.removeAll(listIntersection);





                share|improve this answer


























                • It seems you are keeping the intersection rather than the items not in the intersection.

                  – RealSkeptic
                  Jan 1 at 14:32











                • Oh, sorry, that's true. I'll fix it, thanks!

                  – Dorian Gray
                  Jan 1 at 14:33
















                3














                First of all, you shall add the methods equals and hashCode to your class Foo (see Why do I need to override the equals and hashCode methods in Java?)



                class Foo {
                private int boo;
                private int placeholder = 1;

                public Foo(int boo) {
                this.boo = boo;
                }

                public int getBoo() {
                return boo;
                }

                @Override
                public int hashCode() {
                final int prime = 31;
                int result = 1;
                result = prime * result + boo;
                return result;
                }

                @Override
                public boolean equals(Object obj) {
                if (this == obj)
                return true;
                if (obj == null)
                return false;
                if (!(obj instanceof Foo))
                return false;
                Foo other = (Foo) obj;
                return boo == other.boo;
                }

                }


                Now you can use the removeAll method of List:




                Removes all of this collection's elements that are also contained in
                the specified collection (optional operation). After this call
                returns, this collection will contain no elements in common with the
                specified collection.




                You will have to build a new List notInIntersectList like that:



                    List<Foo> listIntersection = new ArrayList<>(list1);
                listIntersection.removeAll(list2);

                List<Foo> notInIntersectList = new ArrayList<>(list1);
                notInIntersectList.addAll(list2);
                notInIntersectList.removeAll(listIntersection);





                share|improve this answer


























                • It seems you are keeping the intersection rather than the items not in the intersection.

                  – RealSkeptic
                  Jan 1 at 14:32











                • Oh, sorry, that's true. I'll fix it, thanks!

                  – Dorian Gray
                  Jan 1 at 14:33














                3












                3








                3







                First of all, you shall add the methods equals and hashCode to your class Foo (see Why do I need to override the equals and hashCode methods in Java?)



                class Foo {
                private int boo;
                private int placeholder = 1;

                public Foo(int boo) {
                this.boo = boo;
                }

                public int getBoo() {
                return boo;
                }

                @Override
                public int hashCode() {
                final int prime = 31;
                int result = 1;
                result = prime * result + boo;
                return result;
                }

                @Override
                public boolean equals(Object obj) {
                if (this == obj)
                return true;
                if (obj == null)
                return false;
                if (!(obj instanceof Foo))
                return false;
                Foo other = (Foo) obj;
                return boo == other.boo;
                }

                }


                Now you can use the removeAll method of List:




                Removes all of this collection's elements that are also contained in
                the specified collection (optional operation). After this call
                returns, this collection will contain no elements in common with the
                specified collection.




                You will have to build a new List notInIntersectList like that:



                    List<Foo> listIntersection = new ArrayList<>(list1);
                listIntersection.removeAll(list2);

                List<Foo> notInIntersectList = new ArrayList<>(list1);
                notInIntersectList.addAll(list2);
                notInIntersectList.removeAll(listIntersection);





                share|improve this answer















                First of all, you shall add the methods equals and hashCode to your class Foo (see Why do I need to override the equals and hashCode methods in Java?)



                class Foo {
                private int boo;
                private int placeholder = 1;

                public Foo(int boo) {
                this.boo = boo;
                }

                public int getBoo() {
                return boo;
                }

                @Override
                public int hashCode() {
                final int prime = 31;
                int result = 1;
                result = prime * result + boo;
                return result;
                }

                @Override
                public boolean equals(Object obj) {
                if (this == obj)
                return true;
                if (obj == null)
                return false;
                if (!(obj instanceof Foo))
                return false;
                Foo other = (Foo) obj;
                return boo == other.boo;
                }

                }


                Now you can use the removeAll method of List:




                Removes all of this collection's elements that are also contained in
                the specified collection (optional operation). After this call
                returns, this collection will contain no elements in common with the
                specified collection.




                You will have to build a new List notInIntersectList like that:



                    List<Foo> listIntersection = new ArrayList<>(list1);
                listIntersection.removeAll(list2);

                List<Foo> notInIntersectList = new ArrayList<>(list1);
                notInIntersectList.addAll(list2);
                notInIntersectList.removeAll(listIntersection);






                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Jan 1 at 14:50

























                answered Jan 1 at 14:30









                Dorian GrayDorian Gray

                1,511517




                1,511517













                • It seems you are keeping the intersection rather than the items not in the intersection.

                  – RealSkeptic
                  Jan 1 at 14:32











                • Oh, sorry, that's true. I'll fix it, thanks!

                  – Dorian Gray
                  Jan 1 at 14:33



















                • It seems you are keeping the intersection rather than the items not in the intersection.

                  – RealSkeptic
                  Jan 1 at 14:32











                • Oh, sorry, that's true. I'll fix it, thanks!

                  – Dorian Gray
                  Jan 1 at 14:33

















                It seems you are keeping the intersection rather than the items not in the intersection.

                – RealSkeptic
                Jan 1 at 14:32





                It seems you are keeping the intersection rather than the items not in the intersection.

                – RealSkeptic
                Jan 1 at 14:32













                Oh, sorry, that's true. I'll fix it, thanks!

                – Dorian Gray
                Jan 1 at 14:33





                Oh, sorry, that's true. I'll fix it, thanks!

                – Dorian Gray
                Jan 1 at 14:33











                1














                avoid Lambda expressions



                They make code harder to read, and less efficient.



                If you simply use traditional for loops, your code should work... plus, you can use break to stop searching for a second match.



                    List<Foo> notInIntersectList = new ArrayList<Foo>();
                for(Foo li1foo : list1) {
                boolean inBothLists = false;
                for(Foo li2foo : list2) {
                if (li1foo.getBoo() == li2foo.getBoo()) {
                inBothLists = true;
                }
                }
                if (!inBothLists) {
                notInIntersectList.add(li1foo);
                }
                }


                You probably still recognize your code there... Now here's the pro version with imperative coding:



                    List<Foo> notInIntersectList = new ArrayList<Foo>();
                nextfoo: for(Foo li1foo : list1) {
                for(Foo li2foo : list2)
                if (li1foo.getBoo() == li2foo.getBoo())
                continue nextfoo;
                notInIntersectList.add(li1foo);
                }


                This actually has a very clear and explicit logic (and it will make functional fans puke because of the effective "goto"). It's still slow if list2 is huge though, I didn't want to change your algorithm.






                share|improve this answer




























                  1














                  avoid Lambda expressions



                  They make code harder to read, and less efficient.



                  If you simply use traditional for loops, your code should work... plus, you can use break to stop searching for a second match.



                      List<Foo> notInIntersectList = new ArrayList<Foo>();
                  for(Foo li1foo : list1) {
                  boolean inBothLists = false;
                  for(Foo li2foo : list2) {
                  if (li1foo.getBoo() == li2foo.getBoo()) {
                  inBothLists = true;
                  }
                  }
                  if (!inBothLists) {
                  notInIntersectList.add(li1foo);
                  }
                  }


                  You probably still recognize your code there... Now here's the pro version with imperative coding:



                      List<Foo> notInIntersectList = new ArrayList<Foo>();
                  nextfoo: for(Foo li1foo : list1) {
                  for(Foo li2foo : list2)
                  if (li1foo.getBoo() == li2foo.getBoo())
                  continue nextfoo;
                  notInIntersectList.add(li1foo);
                  }


                  This actually has a very clear and explicit logic (and it will make functional fans puke because of the effective "goto"). It's still slow if list2 is huge though, I didn't want to change your algorithm.






                  share|improve this answer


























                    1












                    1








                    1







                    avoid Lambda expressions



                    They make code harder to read, and less efficient.



                    If you simply use traditional for loops, your code should work... plus, you can use break to stop searching for a second match.



                        List<Foo> notInIntersectList = new ArrayList<Foo>();
                    for(Foo li1foo : list1) {
                    boolean inBothLists = false;
                    for(Foo li2foo : list2) {
                    if (li1foo.getBoo() == li2foo.getBoo()) {
                    inBothLists = true;
                    }
                    }
                    if (!inBothLists) {
                    notInIntersectList.add(li1foo);
                    }
                    }


                    You probably still recognize your code there... Now here's the pro version with imperative coding:



                        List<Foo> notInIntersectList = new ArrayList<Foo>();
                    nextfoo: for(Foo li1foo : list1) {
                    for(Foo li2foo : list2)
                    if (li1foo.getBoo() == li2foo.getBoo())
                    continue nextfoo;
                    notInIntersectList.add(li1foo);
                    }


                    This actually has a very clear and explicit logic (and it will make functional fans puke because of the effective "goto"). It's still slow if list2 is huge though, I didn't want to change your algorithm.






                    share|improve this answer













                    avoid Lambda expressions



                    They make code harder to read, and less efficient.



                    If you simply use traditional for loops, your code should work... plus, you can use break to stop searching for a second match.



                        List<Foo> notInIntersectList = new ArrayList<Foo>();
                    for(Foo li1foo : list1) {
                    boolean inBothLists = false;
                    for(Foo li2foo : list2) {
                    if (li1foo.getBoo() == li2foo.getBoo()) {
                    inBothLists = true;
                    }
                    }
                    if (!inBothLists) {
                    notInIntersectList.add(li1foo);
                    }
                    }


                    You probably still recognize your code there... Now here's the pro version with imperative coding:



                        List<Foo> notInIntersectList = new ArrayList<Foo>();
                    nextfoo: for(Foo li1foo : list1) {
                    for(Foo li2foo : list2)
                    if (li1foo.getBoo() == li2foo.getBoo())
                    continue nextfoo;
                    notInIntersectList.add(li1foo);
                    }


                    This actually has a very clear and explicit logic (and it will make functional fans puke because of the effective "goto"). It's still slow if list2 is huge though, I didn't want to change your algorithm.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Jan 1 at 15:29









                    Anony-MousseAnony-Mousse

                    58.6k797162




                    58.6k797162























                        0














                        There is already a library for that:



                        Set<String> wordsWithPrimeLength = ImmutableSet.of("one", "two", "three", "six", "seven", "eight");
                        Set<String> primes = ImmutableSet.of("two", "three", "five", "seven");

                        SetView<String> intersection = Sets.intersection(primes, wordsWithPrimeLength); // contains "two", "three", "seven"
                        // I can use intersection as a Set directly, but copying it can be more efficient if I use it a lot.
                        return intersection.immutableCopy();


                        If you use difference(Set<E> set1, Set<?> set2) instead of intersection(Set<E> set1, Set<?> set2), you will get the difference of the two.



                        With ImmutableSet.copyOf(Collection<? extends E> elements) you can create a Set.



                        It is called Guava and provides many collection operations:
                        https://github.com/google/guava/wiki/CollectionUtilitiesExplained



                        The API: https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/ImmutableSet.html






                        share|improve this answer


























                        • Op wants to have the non-intersected values!

                          – Seelenvirtuose
                          Jan 1 at 14:40











                        • I corrected my answer. Thanks.

                          – Charlie
                          Jan 1 at 14:45
















                        0














                        There is already a library for that:



                        Set<String> wordsWithPrimeLength = ImmutableSet.of("one", "two", "three", "six", "seven", "eight");
                        Set<String> primes = ImmutableSet.of("two", "three", "five", "seven");

                        SetView<String> intersection = Sets.intersection(primes, wordsWithPrimeLength); // contains "two", "three", "seven"
                        // I can use intersection as a Set directly, but copying it can be more efficient if I use it a lot.
                        return intersection.immutableCopy();


                        If you use difference(Set<E> set1, Set<?> set2) instead of intersection(Set<E> set1, Set<?> set2), you will get the difference of the two.



                        With ImmutableSet.copyOf(Collection<? extends E> elements) you can create a Set.



                        It is called Guava and provides many collection operations:
                        https://github.com/google/guava/wiki/CollectionUtilitiesExplained



                        The API: https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/ImmutableSet.html






                        share|improve this answer


























                        • Op wants to have the non-intersected values!

                          – Seelenvirtuose
                          Jan 1 at 14:40











                        • I corrected my answer. Thanks.

                          – Charlie
                          Jan 1 at 14:45














                        0












                        0








                        0







                        There is already a library for that:



                        Set<String> wordsWithPrimeLength = ImmutableSet.of("one", "two", "three", "six", "seven", "eight");
                        Set<String> primes = ImmutableSet.of("two", "three", "five", "seven");

                        SetView<String> intersection = Sets.intersection(primes, wordsWithPrimeLength); // contains "two", "three", "seven"
                        // I can use intersection as a Set directly, but copying it can be more efficient if I use it a lot.
                        return intersection.immutableCopy();


                        If you use difference(Set<E> set1, Set<?> set2) instead of intersection(Set<E> set1, Set<?> set2), you will get the difference of the two.



                        With ImmutableSet.copyOf(Collection<? extends E> elements) you can create a Set.



                        It is called Guava and provides many collection operations:
                        https://github.com/google/guava/wiki/CollectionUtilitiesExplained



                        The API: https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/ImmutableSet.html






                        share|improve this answer















                        There is already a library for that:



                        Set<String> wordsWithPrimeLength = ImmutableSet.of("one", "two", "three", "six", "seven", "eight");
                        Set<String> primes = ImmutableSet.of("two", "three", "five", "seven");

                        SetView<String> intersection = Sets.intersection(primes, wordsWithPrimeLength); // contains "two", "three", "seven"
                        // I can use intersection as a Set directly, but copying it can be more efficient if I use it a lot.
                        return intersection.immutableCopy();


                        If you use difference(Set<E> set1, Set<?> set2) instead of intersection(Set<E> set1, Set<?> set2), you will get the difference of the two.



                        With ImmutableSet.copyOf(Collection<? extends E> elements) you can create a Set.



                        It is called Guava and provides many collection operations:
                        https://github.com/google/guava/wiki/CollectionUtilitiesExplained



                        The API: https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/ImmutableSet.html







                        share|improve this answer














                        share|improve this answer



                        share|improve this answer








                        edited Jan 1 at 14:44

























                        answered Jan 1 at 14:37









                        CharlieCharlie

                        6172926




                        6172926













                        • Op wants to have the non-intersected values!

                          – Seelenvirtuose
                          Jan 1 at 14:40











                        • I corrected my answer. Thanks.

                          – Charlie
                          Jan 1 at 14:45



















                        • Op wants to have the non-intersected values!

                          – Seelenvirtuose
                          Jan 1 at 14:40











                        • I corrected my answer. Thanks.

                          – Charlie
                          Jan 1 at 14:45

















                        Op wants to have the non-intersected values!

                        – Seelenvirtuose
                        Jan 1 at 14:40





                        Op wants to have the non-intersected values!

                        – Seelenvirtuose
                        Jan 1 at 14:40













                        I corrected my answer. Thanks.

                        – Charlie
                        Jan 1 at 14:45





                        I corrected my answer. Thanks.

                        – Charlie
                        Jan 1 at 14:45











                        0














                        I see here four possible solutions:



                        1) Avoid lambda expression following @Anony-Mousse's response



                        2) Include the variable at the class level (not recommended because this boolean is meant for local use):



                        public class Testing {
                        boolean inBothLists = true;

                        public static void main(String args) {
                        List<Foo> notInIntersectList = new ArrayList<Foo>();
                        list1.forEach(li1foo -> {
                        inBothLists = false;
                        list2.forEach(li2foo -> {
                        if (li1foo.getBoo() == li2foo.getBoo()) {
                        inBothLists = true;
                        }
                        });
                        if (!inBothLists) {
                        notInIntersectList.add(li1foo);
                        }
                        });

                        System.out.println("Intersected values:");
                        notInIntersectList.forEach(liInFoo -> {
                        System.out.println(liInFoo);
                        });

                        }


                        3) Using contains method from List (avoiding boolean):



                        List<Foo> notInIntersectList = new ArrayList<Foo>();
                        list1.forEach(li1foo -> {
                        if (!list2.contains(li1foo))
                        notInIntersectList.add(li1foo);
                        });


                        4) Java8 Stream API (already mentioned in another answer and avoiding boolean):



                        List<Foo> notInIntersectList = new ArrayList<Foo>();
                        list1.forEach(li1foo -> {
                        Foo result = list2.stream()
                        .filter(li2foo -> li1foo.getBoo() == li2foo.getBoo() )
                        .findAny()
                        .orElse(null);
                        if (result == null)
                        notInIntersectList.add(li1foo);
                        });


                        I would go for option 1), 3) or 4). I only kept 2.) to show an example using variables inside lambda functions.



                        UPDATE: I found 3) and 4) options in a recent Baeldung post on how to find an Element in a List






                        share|improve this answer






























                          0














                          I see here four possible solutions:



                          1) Avoid lambda expression following @Anony-Mousse's response



                          2) Include the variable at the class level (not recommended because this boolean is meant for local use):



                          public class Testing {
                          boolean inBothLists = true;

                          public static void main(String args) {
                          List<Foo> notInIntersectList = new ArrayList<Foo>();
                          list1.forEach(li1foo -> {
                          inBothLists = false;
                          list2.forEach(li2foo -> {
                          if (li1foo.getBoo() == li2foo.getBoo()) {
                          inBothLists = true;
                          }
                          });
                          if (!inBothLists) {
                          notInIntersectList.add(li1foo);
                          }
                          });

                          System.out.println("Intersected values:");
                          notInIntersectList.forEach(liInFoo -> {
                          System.out.println(liInFoo);
                          });

                          }


                          3) Using contains method from List (avoiding boolean):



                          List<Foo> notInIntersectList = new ArrayList<Foo>();
                          list1.forEach(li1foo -> {
                          if (!list2.contains(li1foo))
                          notInIntersectList.add(li1foo);
                          });


                          4) Java8 Stream API (already mentioned in another answer and avoiding boolean):



                          List<Foo> notInIntersectList = new ArrayList<Foo>();
                          list1.forEach(li1foo -> {
                          Foo result = list2.stream()
                          .filter(li2foo -> li1foo.getBoo() == li2foo.getBoo() )
                          .findAny()
                          .orElse(null);
                          if (result == null)
                          notInIntersectList.add(li1foo);
                          });


                          I would go for option 1), 3) or 4). I only kept 2.) to show an example using variables inside lambda functions.



                          UPDATE: I found 3) and 4) options in a recent Baeldung post on how to find an Element in a List






                          share|improve this answer




























                            0












                            0








                            0







                            I see here four possible solutions:



                            1) Avoid lambda expression following @Anony-Mousse's response



                            2) Include the variable at the class level (not recommended because this boolean is meant for local use):



                            public class Testing {
                            boolean inBothLists = true;

                            public static void main(String args) {
                            List<Foo> notInIntersectList = new ArrayList<Foo>();
                            list1.forEach(li1foo -> {
                            inBothLists = false;
                            list2.forEach(li2foo -> {
                            if (li1foo.getBoo() == li2foo.getBoo()) {
                            inBothLists = true;
                            }
                            });
                            if (!inBothLists) {
                            notInIntersectList.add(li1foo);
                            }
                            });

                            System.out.println("Intersected values:");
                            notInIntersectList.forEach(liInFoo -> {
                            System.out.println(liInFoo);
                            });

                            }


                            3) Using contains method from List (avoiding boolean):



                            List<Foo> notInIntersectList = new ArrayList<Foo>();
                            list1.forEach(li1foo -> {
                            if (!list2.contains(li1foo))
                            notInIntersectList.add(li1foo);
                            });


                            4) Java8 Stream API (already mentioned in another answer and avoiding boolean):



                            List<Foo> notInIntersectList = new ArrayList<Foo>();
                            list1.forEach(li1foo -> {
                            Foo result = list2.stream()
                            .filter(li2foo -> li1foo.getBoo() == li2foo.getBoo() )
                            .findAny()
                            .orElse(null);
                            if (result == null)
                            notInIntersectList.add(li1foo);
                            });


                            I would go for option 1), 3) or 4). I only kept 2.) to show an example using variables inside lambda functions.



                            UPDATE: I found 3) and 4) options in a recent Baeldung post on how to find an Element in a List






                            share|improve this answer















                            I see here four possible solutions:



                            1) Avoid lambda expression following @Anony-Mousse's response



                            2) Include the variable at the class level (not recommended because this boolean is meant for local use):



                            public class Testing {
                            boolean inBothLists = true;

                            public static void main(String args) {
                            List<Foo> notInIntersectList = new ArrayList<Foo>();
                            list1.forEach(li1foo -> {
                            inBothLists = false;
                            list2.forEach(li2foo -> {
                            if (li1foo.getBoo() == li2foo.getBoo()) {
                            inBothLists = true;
                            }
                            });
                            if (!inBothLists) {
                            notInIntersectList.add(li1foo);
                            }
                            });

                            System.out.println("Intersected values:");
                            notInIntersectList.forEach(liInFoo -> {
                            System.out.println(liInFoo);
                            });

                            }


                            3) Using contains method from List (avoiding boolean):



                            List<Foo> notInIntersectList = new ArrayList<Foo>();
                            list1.forEach(li1foo -> {
                            if (!list2.contains(li1foo))
                            notInIntersectList.add(li1foo);
                            });


                            4) Java8 Stream API (already mentioned in another answer and avoiding boolean):



                            List<Foo> notInIntersectList = new ArrayList<Foo>();
                            list1.forEach(li1foo -> {
                            Foo result = list2.stream()
                            .filter(li2foo -> li1foo.getBoo() == li2foo.getBoo() )
                            .findAny()
                            .orElse(null);
                            if (result == null)
                            notInIntersectList.add(li1foo);
                            });


                            I would go for option 1), 3) or 4). I only kept 2.) to show an example using variables inside lambda functions.



                            UPDATE: I found 3) and 4) options in a recent Baeldung post on how to find an Element in a List







                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Jan 1 at 20:31

























                            answered Jan 1 at 15:44









                            Carlos CaveroCarlos Cavero

                            1,0621619




                            1,0621619






























                                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.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53996101%2fjava-proper-way-of-creating-a-list-containing-all-not-in-intersect-elements-fro%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

                                MongoDB - Not Authorized To Execute Command

                                How to fix TextFormField cause rebuild widget in Flutter

                                Npm cannot find a required file even through it is in the searched directory