--- old/src/share/classes/java/util/Collections.java 2010-12-23 11:42:07.000000000 -0800 +++ new/src/share/classes/java/util/Collections.java 2010-12-23 11:42:07.000000000 -0800 @@ -3714,45 +3714,90 @@ } /** - * Returns true if the two specified collections have no + * Returns {@code true} if the two specified collections have no * elements in common. * *

Care must be exercised if this method is used on collections that - * do not comply with the general contract for Collection. + * do not comply with the general contract for {@code Collection}. * Implementations may elect to iterate over either collection and test * for containment in the other collection (or to perform any equivalent * computation). If either collection uses a nonstandard equality test - * (as does a {@link SortedSet} whose ordering is not compatible with - * equals, or the key set of an {@link IdentityHashMap}), both + * (as does a {@link SortedSet} whose ordering is not compatible with + * equals, or the key set of an {@link IdentityHashMap}), both * collections must use the same nonstandard equality test, or the * result of this method is undefined. + * + *

Care must also be exercised when using collections that have + * restrictions on the elements that they may contain. Collection + * implementations are allowed to throw exceptions for any operation + * involving elements they deem ineligible. For absolute safety the + * specified collections should contain only elements which are + * eligible elements for both collections. * *

Note that it is permissible to pass the same collection in both - * parameters, in which case the method will return true if and only if - * the collection is empty. + * parameters, in which case the method will return {@code true} if and + * only if the collection is empty. * * @param c1 a collection * @param c2 a collection - * @throws NullPointerException if either collection is null + * @return {@code true} if the two specified collections have no + * elements in common. + * @throws NullPointerException if either collection is {@code null}. + * @throws NullPointerException if one collection contains a {@code null} + * element and {@code null} is not an eligible element for the other collection. + * (optional) + * @throws ClassCastException if one collection contains an element that is + * of a type which is ineligible for the other collection. (optional) * @since 1.5 */ public static boolean disjoint(Collection c1, Collection c2) { - /* - * We're going to iterate through c1 and test for inclusion in c2. - * If c1 is a Set and c2 isn't, swap the collections. Otherwise, - * place the shorter collection in c1. Hopefully this heuristic - * will minimize the cost of the operation. - */ - if ((c1 instanceof Set) && !(c2 instanceof Set) || - (c1.size() > c2.size())) { - Collection tmp = c1; - c1 = c2; - c2 = tmp; + // The collection to be used for contains(), Preference is given to + // Sets as their contains() impl should be less than O(N/2). + Collection contains = c2; + // The collection to be iterated. As performance of Set's contains() + // should be less than O(N/2), iteration is given to the remaining + // collection. For collections who's contains() are of the same + // complexity then best performance is achieved by iterating the + // smaller collection. + Collection iterate = c1; + + // Performance optimization cases. The heuristics: + // 1. Generally iterate over c1. + // 2. If c1 is a Set then iterate over c2. + // 3. If either collection is empty then result is always true. + // 4. Iterate over the smaller Collection. + if (c1 instanceof Set) { + // As Set's contains() performs better (less than O(N/2)) + //than mere Collection's,iterate on c2. + iterate = c2; + contains = c1; + } else if (!(c2 instanceof Set)) { + // Both are mere Collections. Iterate over smaller collection. + // E.g. if c1 contains 3 elements and c2 contains 50 elements and + // assuming contains() requires ceiling(n/2) comparisons then + // checking for all c1 elements in c2 would require 75 comparisons + // vs. all c2 elements in c1 would require 100 comparisons. + int c1size = c1.size(); + int c2size = c2.size(); + if (c1size == 0 || c2size == 0) { + // One (or both) collections is/are empty. Nothing will match. + return true; + } + + if (c1size > c2size) { + iterate = c2; + contains = c1; + } + } + + for (Object e : iterate) { + if (contains.contains(e)) { + // Found a common element. Collections are not disjoint. + return false; + } } - for (Object e : c1) - if (c2.contains(e)) - return false; + // No common elements were found. return true; }