docs: public static <E> Set<E> union(final Set<? extends E> set1, final Set<? extends E> set2) {
          checkArgumentNotNull(set1, "set1");
          checkArgumentNotNull(set2, "set2");
  
          // Set 2 minus set 1
          final Set<E> difference = new HashSet<>(set2);
          difference.removeAll(set1);
          // Following stream does not compile on some JDKs
          // See also https://bugs.openjdk.java.net/browse/JDK-8051443
          // set2.stream().filter((e) -> !set1.contains(e)).collect(Collectors.toSet());
  
          return new AbstractSet<E>() {
  
              @Override
              public Iterator<E> iterator() {
                  final Iterator<E> iterator = Iterators.concat(ImmutableList.of(set1.iterator(), difference.iterator()).iterator());
                  // Remove operation is not supported by default
                  return new Iterator<E>() {
                      @Override
                      public boolean hasNext() {
                          return iterator.hasNext();
                      }
  
                      @Override
                      public E next() {
                          return iterator.next();
                      }
                  };
              }
  
              @Override
              public int size() {
                  return set1.size() + difference.size();
              }
  
              @Override
              public boolean isEmpty() {
                  return set1.isEmpty() && difference.isEmpty();
              }
  
              @Override
              public boolean contains(Object o) {
                  return set1.contains(o) || difference.contains(o);
              }
          };
      }