/* * Copyright (C) 2007 The Guava Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.common.base; import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.regex.Pattern; import javax.annotation.Nullable; /** * Static utility methods pertaining to {@code Predicate} instances. * *

All methods returns serializable predicates as long as they're given * serializable parameters. * * @author Kevin Bourrillion * @since 2.0 (imported from Google Collections Library) */ @GwtCompatible(emulated = true) public final class Predicates { private Predicates() {} // TODO(kevinb): considering having these implement a VisitablePredicate // interface which specifies an accept(PredicateVisitor) method. /** * Returns a predicate that always evaluates to {@code true}. */ @GwtCompatible(serializable = true) public static Predicate alwaysTrue() { return ObjectPredicate.ALWAYS_TRUE.withNarrowedType(); } /** * Returns a predicate that always evaluates to {@code false}. */ @GwtCompatible(serializable = true) public static Predicate alwaysFalse() { return ObjectPredicate.ALWAYS_FALSE.withNarrowedType(); } /** * Returns a predicate that evaluates to {@code true} if the object reference * being tested is null. */ @GwtCompatible(serializable = true) public static Predicate isNull() { return ObjectPredicate.IS_NULL.withNarrowedType(); } /** * Returns a predicate that evaluates to {@code true} if the object reference * being tested is not null. */ @GwtCompatible(serializable = true) public static Predicate notNull() { return ObjectPredicate.NOT_NULL.withNarrowedType(); } /** * Returns a predicate that evaluates to {@code true} if the given predicate * evaluates to {@code false}. */ public static Predicate not(Predicate predicate) { return new NotPredicate(predicate); } /** * Returns a predicate that evaluates to {@code true} if each of its * components evaluates to {@code true}. The components are evaluated in * order, and evaluation will be "short-circuited" as soon as a false * predicate is found. It defensively copies the iterable passed in, so future * changes to it won't alter the behavior of this predicate. If {@code * components} is empty, the returned predicate will always evaluate to {@code * true}. */ public static Predicate and( Iterable> components) { return new AndPredicate(defensiveCopy(components)); } /** * Returns a predicate that evaluates to {@code true} if each of its * components evaluates to {@code true}. The components are evaluated in * order, and evaluation will be "short-circuited" as soon as a false * predicate is found. It defensively copies the array passed in, so future * changes to it won't alter the behavior of this predicate. If {@code * components} is empty, the returned predicate will always evaluate to {@code * true}. */ public static Predicate and(Predicate... components) { return new AndPredicate(defensiveCopy(components)); } /** * Returns a predicate that evaluates to {@code true} if both of its * components evaluate to {@code true}. The components are evaluated in * order, and evaluation will be "short-circuited" as soon as a false * predicate is found. */ public static Predicate and(Predicate first, Predicate second) { return new AndPredicate(Predicates.asList( checkNotNull(first), checkNotNull(second))); } /** * Returns a predicate that evaluates to {@code true} if any one of its * components evaluates to {@code true}. The components are evaluated in * order, and evaluation will be "short-circuited" as soon as a * true predicate is found. It defensively copies the iterable passed in, so * future changes to it won't alter the behavior of this predicate. If {@code * components} is empty, the returned predicate will always evaluate to {@code * false}. */ public static Predicate or( Iterable> components) { return new OrPredicate(defensiveCopy(components)); } /** * Returns a predicate that evaluates to {@code true} if any one of its * components evaluates to {@code true}. The components are evaluated in * order, and evaluation will be "short-circuited" as soon as a * true predicate is found. It defensively copies the array passed in, so * future changes to it won't alter the behavior of this predicate. If {@code * components} is empty, the returned predicate will always evaluate to {@code * false}. */ public static Predicate or(Predicate... components) { return new OrPredicate(defensiveCopy(components)); } /** * Returns a predicate that evaluates to {@code true} if either of its * components evaluates to {@code true}. The components are evaluated in * order, and evaluation will be "short-circuited" as soon as a * true predicate is found. */ public static Predicate or( Predicate first, Predicate second) { return new OrPredicate(Predicates.asList( checkNotNull(first), checkNotNull(second))); } /** * Returns a predicate that evaluates to {@code true} if the object being * tested {@code equals()} the given target or both are null. */ public static Predicate equalTo(@Nullable T target) { return (target == null) ? Predicates.isNull() : new IsEqualToPredicate(target); } /** * Returns a predicate that evaluates to {@code true} if the object being * tested is an instance of the given class. If the object being tested * is {@code null} this predicate evaluates to {@code false}. * *

If you want to filter an {@code Iterable} to narrow its type, consider * using {@link com.google.common.collect.Iterables#filter(Iterable, Class)} * in preference. * *

Warning: contrary to the typical assumptions about predicates (as * documented at {@link Predicate#apply}), the returned predicate may not be * consistent with equals. For example, {@code * instanceOf(ArrayList.class)} will yield different results for the two equal * instances {@code Lists.newArrayList(1)} and {@code Arrays.asList(1)}. */ @GwtIncompatible("Class.isInstance") public static Predicate instanceOf(Class clazz) { return new InstanceOfPredicate(clazz); } /** * Returns a predicate that evaluates to {@code true} if the class being * tested is assignable from the given class. The returned predicate * does not allow null inputs. * * @since 10.0 */ @GwtIncompatible("Class.isAssignableFrom") @Beta public static Predicate> assignableFrom(Class clazz) { return new AssignableFromPredicate(clazz); } /** * Returns a predicate that evaluates to {@code true} if the object reference * being tested is a member of the given collection. It does not defensively * copy the collection passed in, so future changes to it will alter the * behavior of the predicate. * *

This method can technically accept any {@code Collection}, but using * a typed collection helps prevent bugs. This approach doesn't block any * potential users since it is always possible to use {@code * Predicates.in()}. * * @param target the collection that may contain the function input */ public static Predicate in(Collection target) { return new InPredicate(target); } /** * Returns the composition of a function and a predicate. For every {@code x}, * the generated predicate returns {@code predicate(function(x))}. * * @return the composition of the provided function and predicate */ public static Predicate compose( Predicate predicate, Function function) { return new CompositionPredicate(predicate, function); } /** * Returns a predicate that evaluates to {@code true} if the * {@code CharSequence} being tested contains any match for the given * regular expression pattern. The test used is equivalent to * {@code Pattern.compile(pattern).matcher(arg).find()} * * @throws java.util.regex.PatternSyntaxException if the pattern is invalid * @since 3.0 */ @GwtIncompatible(value = "java.util.regex.Pattern") public static Predicate containsPattern(String pattern) { return new ContainsPatternPredicate(pattern); } /** * Returns a predicate that evaluates to {@code true} if the * {@code CharSequence} being tested contains any match for the given * regular expression pattern. The test used is equivalent to * {@code pattern.matcher(arg).find()} * * @since 3.0 */ @GwtIncompatible(value = "java.util.regex.Pattern") public static Predicate contains(Pattern pattern) { return new ContainsPatternPredicate(pattern); } // End public API, begin private implementation classes. // Package private for GWT serialization. enum ObjectPredicate implements Predicate { ALWAYS_TRUE { @Override public boolean apply(@Nullable Object o) { return true; } }, ALWAYS_FALSE { @Override public boolean apply(@Nullable Object o) { return false; } }, IS_NULL { @Override public boolean apply(@Nullable Object o) { return o == null; } }, NOT_NULL { @Override public boolean apply(@Nullable Object o) { return o != null; } }; @SuppressWarnings("unchecked") // these Object predicates work for any T Predicate withNarrowedType() { return (Predicate) this; } } /** @see Predicates#not(Predicate) */ private static class NotPredicate implements Predicate, Serializable { final Predicate predicate; NotPredicate(Predicate predicate) { this.predicate = checkNotNull(predicate); } @Override public boolean apply(T t) { return !predicate.apply(t); } @Override public int hashCode() { return ~predicate.hashCode(); } @Override public boolean equals(@Nullable Object obj) { if (obj instanceof NotPredicate) { NotPredicate that = (NotPredicate) obj; return predicate.equals(that.predicate); } return false; } @Override public String toString() { return "Not(" + predicate.toString() + ")"; } private static final long serialVersionUID = 0; } private static final Joiner COMMA_JOINER = Joiner.on(","); /** @see Predicates#and(Iterable) */ private static class AndPredicate implements Predicate, Serializable { private final List> components; private AndPredicate(List> components) { this.components = components; } @Override public boolean apply(T t) { for (int i = 0; i < components.size(); i++) { if (!components.get(i).apply(t)) { return false; } } return true; } @Override public int hashCode() { // 0x12472c2c is a random number to help avoid collisions with OrPredicate return components.hashCode() + 0x12472c2c; } @Override public boolean equals(@Nullable Object obj) { if (obj instanceof AndPredicate) { AndPredicate that = (AndPredicate) obj; return components.equals(that.components); } return false; } @Override public String toString() { return "And(" + COMMA_JOINER.join(components) + ")"; } private static final long serialVersionUID = 0; } /** @see Predicates#or(Iterable) */ private static class OrPredicate implements Predicate, Serializable { private final List> components; private OrPredicate(List> components) { this.components = components; } @Override public boolean apply(T t) { for (int i = 0; i < components.size(); i++) { if (components.get(i).apply(t)) { return true; } } return false; } @Override public int hashCode() { // 0x053c91cf is a random number to help avoid collisions with AndPredicate return components.hashCode() + 0x053c91cf; } @Override public boolean equals(@Nullable Object obj) { if (obj instanceof OrPredicate) { OrPredicate that = (OrPredicate) obj; return components.equals(that.components); } return false; } @Override public String toString() { return "Or(" + COMMA_JOINER.join(components) + ")"; } private static final long serialVersionUID = 0; } /** @see Predicates#equalTo(Object) */ private static class IsEqualToPredicate implements Predicate, Serializable { private final T target; private IsEqualToPredicate(T target) { this.target = target; } @Override public boolean apply(T t) { return target.equals(t); } @Override public int hashCode() { return target.hashCode(); } @Override public boolean equals(@Nullable Object obj) { if (obj instanceof IsEqualToPredicate) { IsEqualToPredicate that = (IsEqualToPredicate) obj; return target.equals(that.target); } return false; } @Override public String toString() { return "IsEqualTo(" + target + ")"; } private static final long serialVersionUID = 0; } /** @see Predicates#instanceOf(Class) */ @GwtIncompatible("Class.isInstance") private static class InstanceOfPredicate implements Predicate, Serializable { private final Class clazz; private InstanceOfPredicate(Class clazz) { this.clazz = checkNotNull(clazz); } @Override public boolean apply(@Nullable Object o) { return clazz.isInstance(o); } @Override public int hashCode() { return clazz.hashCode(); } @Override public boolean equals(@Nullable Object obj) { if (obj instanceof InstanceOfPredicate) { InstanceOfPredicate that = (InstanceOfPredicate) obj; return clazz == that.clazz; } return false; } @Override public String toString() { return "IsInstanceOf(" + clazz.getName() + ")"; } private static final long serialVersionUID = 0; } /** @see Predicates#assignableFrom(Class) */ @GwtIncompatible("Class.isAssignableFrom") private static class AssignableFromPredicate implements Predicate>, Serializable { private final Class clazz; private AssignableFromPredicate(Class clazz) { this.clazz = checkNotNull(clazz); } @Override public boolean apply(Class input) { return clazz.isAssignableFrom(input); } @Override public int hashCode() { return clazz.hashCode(); } @Override public boolean equals(@Nullable Object obj) { if (obj instanceof AssignableFromPredicate) { AssignableFromPredicate that = (AssignableFromPredicate) obj; return clazz == that.clazz; } return false; } @Override public String toString() { return "IsAssignableFrom(" + clazz.getName() + ")"; } private static final long serialVersionUID = 0; } /** @see Predicates#in(Collection) */ private static class InPredicate implements Predicate, Serializable { private final Collection target; private InPredicate(Collection target) { this.target = checkNotNull(target); } @Override public boolean apply(T t) { try { return target.contains(t); } catch (NullPointerException e) { return false; } catch (ClassCastException e) { return false; } } @Override public boolean equals(@Nullable Object obj) { if (obj instanceof InPredicate) { InPredicate that = (InPredicate) obj; return target.equals(that.target); } return false; } @Override public int hashCode() { return target.hashCode(); } @Override public String toString() { return "In(" + target + ")"; } private static final long serialVersionUID = 0; } /** @see Predicates#compose(Predicate, Function) */ private static class CompositionPredicate implements Predicate, Serializable { final Predicate p; final Function f; private CompositionPredicate(Predicate p, Function f) { this.p = checkNotNull(p); this.f = checkNotNull(f); } @Override public boolean apply(A a) { return p.apply(f.apply(a)); } @Override public boolean equals(@Nullable Object obj) { if (obj instanceof CompositionPredicate) { CompositionPredicate that = (CompositionPredicate) obj; return f.equals(that.f) && p.equals(that.p); } return false; } @Override public int hashCode() { return f.hashCode() ^ p.hashCode(); } @Override public String toString() { return p.toString() + "(" + f.toString() + ")"; } private static final long serialVersionUID = 0; } /** * @see Predicates#contains(Pattern) * @see Predicates#containsPattern(String) */ @GwtIncompatible("Only used by other GWT-incompatible code.") private static class ContainsPatternPredicate implements Predicate, Serializable { final Pattern pattern; ContainsPatternPredicate(Pattern pattern) { this.pattern = checkNotNull(pattern); } ContainsPatternPredicate(String patternStr) { this(Pattern.compile(patternStr)); } @Override public boolean apply(CharSequence t) { return pattern.matcher(t).find(); } @Override public int hashCode() { // Pattern uses Object.hashCode, so we have to reach // inside to build a hashCode consistent with equals. return Objects.hashCode(pattern.pattern(), pattern.flags()); } @Override public boolean equals(@Nullable Object obj) { if (obj instanceof ContainsPatternPredicate) { ContainsPatternPredicate that = (ContainsPatternPredicate) obj; // Pattern uses Object (identity) equality, so we have to reach // inside to compare individual fields. return Objects.equal(pattern.pattern(), that.pattern.pattern()) && Objects.equal(pattern.flags(), that.pattern.flags()); } return false; } @Override public String toString() { return Objects.toStringHelper(this) .add("pattern", pattern) .add("pattern.flags", Integer.toHexString(pattern.flags())) .toString(); } private static final long serialVersionUID = 0; } @SuppressWarnings("unchecked") private static List> asList( Predicate first, Predicate second) { return Arrays.>asList(first, second); } private static List defensiveCopy(T... array) { return defensiveCopy(Arrays.asList(array)); } static List defensiveCopy(Iterable iterable) { ArrayList list = new ArrayList(); for (T element : iterable) { list.add(checkNotNull(element)); } return list; } }