android/guava/src/com/google/common/collect/Sets.java
public static <E> SetView<E> intersection(final Set<E> set1, final Set<?> set2) {
    checkNotNull(set1, "set1");
    checkNotNull(set2, "set2");

    return new SetView<E>() {
      @Override
      public UnmodifiableIterator<E> iterator() {
        return new AbstractIterator<E>() {
          final Iterator<E> itr = set1.iterator();

          @Override
          protected E computeNext() {
            while (itr.hasNext()) {
              E e = itr.next();
              if (set2.contains(e)) {
                return e;
              }
            }
            return endOfData();
          }
        };
      }

      @Override
      public int size() {
        int size = 0;
        for (E e : set1) {
          if (set2.contains(e)) {
            size++;
          }
        }
        return size;
      }

      @Override
      public boolean isEmpty() {
        return Collections.disjoint(set2, set1);
      }

      @Override
      public boolean contains(Object object) {
        return set1.contains(object) && set2.contains(object);
      }

      @Override
      public boolean containsAll(Collection<?> collection) {
        return set1.containsAll(collection) && set2.containsAll(collection);
      }
    };
  }
public static <E> SetView<E> intersection(final Set<E> set1, final Set<?> set2) {
    checkNotNull(set1, "set1");
    checkNotNull(set2, "set2");

    return new SetView<E>() {
      @Override
      public UnmodifiableIterator<E> iterator() {
        return new AbstractIterator<E>() {
          final Iterator<E> itr = set1.iterator();

          @Override
          protected E computeNext() {
            while (itr.hasNext()) {
              E e = itr.next();
              if (set2.contains(e)) {
                return e;
              }
            }
            return endOfData();
          }
        };
      }

      @Override
      public int size() {
        int size = 0;
        for (E e : set1) {
          if (set2.contains(e)) {
            size++;
          }
        }
        return size;
      }

      @Override
      public boolean isEmpty() {
        return Collections.disjoint(set2, set1);
      }

      @Override
      public boolean contains(Object object) {
        return set1.contains(object) && set2.contains(object);
      }

      @Override
      public boolean containsAll(Collection<?> collection) {
        return set1.containsAll(collection) && set2.containsAll(collection);
      }
    };
  }
Returns an unmodifiable <b>view</b> of the intersection of two sets. The returned set contains
all elements that are contained by both backing sets. The iteration order of the returned set
matches that of {@code set1}.

<p>Results are undefined if {@code set1} and {@code set2} are sets based on different
equivalence relations (as {@code HashSet}, {@code TreeSet}, and the keySet of an {@code
IdentityHashMap} all are).

<p><b>Note:</b> The returned view performs slightly better when {@code set1} is the smaller of
the two sets. If you have reason to believe one of your sets will generally be smaller than the
other, pass it first. Unfortunately, since this method sets the generic type of the returned
set based on the type of the first set passed, this could in rare cases force you to make a
cast, for example:

<pre>{@code
Set<Object> aFewBadObjects = ...
Set<String> manyBadStrings = ...

// impossible for a non-String to be in the intersection
SuppressWarnings("unchecked")
Set<String> badStrings = (Set) Sets.intersection(
aFewBadObjects, manyBadStrings);
}</pre>

<p>This is unfortunate, but should come up only very rarely.