2023-08-17
原文作者:LifeIsForSharing 原文地址:https://solang.blog.csdn.net/article/details/105101316

Functional idioms:Guava的函数习语可以大大简化代码。

1.注意事项

Java 8包括java.util.functionjava.util.stream软件包,它们取代了Guava函数编程类,用于该语言级别的项目。

虽然Guava的函数工具类可在Java 8之前的Java版本上使用,但没有Java 8的函数式编程需要笨拙且冗长地使用匿名类。

过度使用Guava的函数式编程习语用法会导致冗长、混乱、不可读和低效的代码。这些是迄今为止最容易(也是最常见)的Guava滥用部分,当你费力地使代码变成"一行"时,Guava团队就会哭泣。

比较以下代码:

    Function<String, Integer> lengthFunction = new Function<String, Integer>() {
      public Integer apply(String string) {
        return string.length();
      }
    };
    Predicate<String> allCaps = new Predicate<String>() {
      public boolean apply(String string) {
        return CharMatcher.javaUpperCase().matchesAllOf(string);
      }
    };
    Multiset<Integer> lengths = HashMultiset.create(
      Iterables.transform(Iterables.filter(strings, allCaps), lengthFunction));

或流利的版本

    Multiset<Integer> lengths = HashMultiset.create(
      FluentIterable.from(strings)
        .filter(new Predicate<String>() {
           public boolean apply(String string) {
             return CharMatcher.javaUpperCase().matchesAllOf(string);
           }
         })
        .transform(new Function<String, Integer>() {
           public Integer apply(String string) {
             return string.length();
           }
         }));

同:

    Multiset<Integer> lengths = HashMultiset.create();
    for (String string : strings) {
      if (CharMatcher.javaUpperCase().matchesAllOf(string)) {
        lengths.add(string.length());
      }
    }

即使使用静态导入,甚至将FunctionPredicate声明移至其它文件,第一个实现也不太简洁,可读性和效率较低。

命令式代码应该是默认选择,也是Java 7的第一选择。除非绝对确定以下其中一项,否则不应使用函数式用法:

  • 使用函数式用法将节省整个项目的代码行。在上面的示例中,"函数式"版本使用11行,而命令式版本使用6行。将函数的定义移至另一个文件或常量中并没有帮助。
  • 为了提高效率,你需要对转换后的集合进行延迟计算的视图,并且不能满足显式计算的集合。另外,你已经阅读并重新阅读了Effective Java,第55项,除了遵循这些说明之外,你实际上已经完成了基准测试以证明该版本更快,并且可以引用数字进行证明。

请确保在使用Guava的函数工具类时,传统的命令式处理方式并没有更好的可读性。试着写出来。真的那么糟糕吗?这比你将要尝试的笨拙的函数式方法更具可读性吗?

2.函数和谓语

本文仅讨论那些直接处理FunctionPredicate的Guava功能。其它一些工具与“函数式”相关联,例如级联和可在恒定时间内返回视图的其它方法。尝试查看集合工具文章。

Guava提供了两个基本的"函数式"接口:

  • Function<A, B>具有单个方法B apply(A input)。通常希望Function的实例具有参照透明性——无副作用——并且与equals一致,即a.equals(b)表示function.apply(a).equals(function.apply(b))
  • Predicate<T>具有单个方法boolean apply(T input)。通常希望Predicate实例是无副作用的并且与equals一致。

3.特殊谓语

字符有自己的Predicate的专用版本CharMatcher,它通常对于这些需求而言更加高效和有用。CharMatcher已经实现了Predicate<Character>,可以相应地使用,而从PredicateCharMatcher的转换可以使用CharMatcher.forPredicate完成。有关详细信息,请参阅CharMatcher文章

此外,对于可比较的类型和基于比较的谓语,可以使用Range类型实现大多数需求,它实现了不可变的范围。Range类型实现了Predicate,测试是否包含在范围内。例如,Range.atMost(2)是一个完全有效的Predicate<Integer>。有关使用范围的更多详细信息参见[Range文章]。

4.操作函数和谓语

Functions中提供了简单的Function构造和操作方法,包括:

有关详细信息,请查阅Javadoc。

Predicates谓语中有很多可用的构造和操作方法,示例包括:

有关详细信息,请查阅Javadoc。

5.使用

Guava提供了许多使用函数和谓语来操作集合的工具。这些通常可以在集合工具类IterablesListsSetsMapsMultimaps等中找到。

6.谓语

谓语最基本的用途是过滤集合。所有Guava过滤器方法都返回视图。

集合类型 过滤方法
Iterable Iterables.filter(Iterable,Predicate)FluentIterable.filter(Predicate)

7.使用示例

7.1Function

    import com.google.common.annotations.GwtIncompatible;
    import com.google.common.base.*;
    import com.google.common.collect.ImmutableMap;
    import com.google.common.collect.Maps;
    import com.google.common.testing.ClassSanityTester;
    import com.google.common.testing.EqualsTester;
    import com.google.common.testing.NullPointerTester;
    import com.google.common.testing.SerializableTester;
    import junit.framework.TestCase;
    
    import java.io.Serializable;
    import java.util.Map;
    
    public class FunctionsTest extends TestCase {
    
        public void testIdentity_same() {
            Function<String, String> identity = Functions.identity();
            assertNull(identity.apply(null));
            assertSame("foo", identity.apply("foo"));
        }
    
        public void testIdentity_notSame() {
            Function<Long, Long> identity = Functions.identity();
            assertNotSame(new Long(135135L), identity.apply(new Long(135135L)));
        }
    
        @GwtIncompatible // SerializableTester
        public void testIdentitySerializable() {
            checkCanReserializeSingleton(Functions.identity());
        }
    
        public void testToStringFunction_apply() {
            assertEquals("3", Functions.toStringFunction().apply(3));
            assertEquals("hiya", Functions.toStringFunction().apply("hiya"));
            assertEquals(
                    "I'm a string",
                    Functions.toStringFunction()
                            .apply(
                                    new Object() {
                                        @Override
                                        public String toString() {
                                            return "I'm a string";
                                        }
                                    }));
            try {
                Functions.toStringFunction().apply(null);
                fail("expected NullPointerException");
            } catch (NullPointerException expected) {
            }
        }
    
        @GwtIncompatible // SerializableTester
        public void testToStringFunctionSerializable() {
            checkCanReserializeSingleton(Functions.toStringFunction());
        }
    
        @GwtIncompatible // NullPointerTester
        public void testNullPointerExceptions() {
            NullPointerTester tester = new NullPointerTester();
            tester.testAllPublicStaticMethods(Functions.class);
        }
    
        public void testForMapWithoutDefault() {
            Map<String, Integer> map = Maps.newHashMap();
            map.put("One", 1);
            map.put("Three", 3);
            map.put("Null", null);
            Function<String, Integer> function = Functions.forMap(map);
    
            assertEquals(1, function.apply("One").intValue());
            assertEquals(3, function.apply("Three").intValue());
            assertNull(function.apply("Null"));
    
            try {
                function.apply("Two");
                fail();
            } catch (IllegalArgumentException expected) {
            }
    
            new EqualsTester()
                    .addEqualityGroup(function, Functions.forMap(map))
                    .addEqualityGroup(Functions.forMap(map, 42))
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testForMapWithoutDefaultSerializable() {
            checkCanReserialize(Functions.forMap(ImmutableMap.of(1, 2)));
        }
    
        public void testForMapWithDefault() {
            Map<String, Integer> map = Maps.newHashMap();
            map.put("One", 1);
            map.put("Three", 3);
            map.put("Null", null);
            Function<String, Integer> function = Functions.forMap(map, 42);
    
            assertEquals(1, function.apply("One").intValue());
            assertEquals(42, function.apply("Two").intValue());
            assertEquals(3, function.apply("Three").intValue());
            assertNull(function.apply("Null"));
    
            new EqualsTester()
                    .addEqualityGroup(function, Functions.forMap(map, 42))
                    .addEqualityGroup(Functions.forMap(map))
                    .addEqualityGroup(Functions.forMap(map, null))
                    .addEqualityGroup(Functions.forMap(map, 43))
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testForMapWithDefault_includeSerializable() {
            Map<String, Integer> map = Maps.newHashMap();
            map.put("One", 1);
            map.put("Three", 3);
            Function<String, Integer> function = Functions.forMap(map, 42);
    
            assertEquals(1, function.apply("One").intValue());
            assertEquals(42, function.apply("Two").intValue());
            assertEquals(3, function.apply("Three").intValue());
    
            new EqualsTester()
                    .addEqualityGroup(
                            function, Functions.forMap(map, 42), SerializableTester.reserialize(function))
                    .addEqualityGroup(Functions.forMap(map))
                    .addEqualityGroup(Functions.forMap(map, null))
                    .addEqualityGroup(Functions.forMap(map, 43))
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testForMapWithDefaultSerializable() {
            checkCanReserialize(Functions.forMap(ImmutableMap.of(1, 2), 3));
        }
    
        public void testForMapWithDefault_null() {
            ImmutableMap<String, Integer> map = ImmutableMap.of("One", 1);
            Function<String, Integer> function = Functions.forMap(map, null);
    
            assertEquals((Integer) 1, function.apply("One"));
            assertNull(function.apply("Two"));
    
            // check basic sanity of equals and hashCode
            new EqualsTester()
                    .addEqualityGroup(function)
                    .addEqualityGroup(Functions.forMap(map, 1))
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testForMapWithDefault_null_compareWithSerializable() {
            ImmutableMap<String, Integer> map = ImmutableMap.of("One", 1);
            Function<String, Integer> function = Functions.forMap(map, null);
    
            assertEquals((Integer) 1, function.apply("One"));
            assertNull(function.apply("Two"));
    
            // check basic sanity of equals and hashCode
            new EqualsTester()
                    .addEqualityGroup(function, SerializableTester.reserialize(function))
                    .addEqualityGroup(Functions.forMap(map, 1))
                    .testEquals();
        }
    
        public void testForMapWildCardWithDefault() {
            Map<String, Integer> map = Maps.newHashMap();
            map.put("One", 1);
            map.put("Three", 3);
            Number number = Double.valueOf(42);
            Function<String, Number> function = Functions.forMap(map, number);
    
            assertEquals(1, function.apply("One").intValue());
            assertEquals(number, function.apply("Two"));
            assertEquals(3L, function.apply("Three").longValue());
        }
    
        public void testComposition() {
            Map<String, Integer> mJapaneseToInteger = Maps.newHashMap();
            mJapaneseToInteger.put("Ichi", 1);
            mJapaneseToInteger.put("Ni", 2);
            mJapaneseToInteger.put("San", 3);
            Function<String, Integer> japaneseToInteger = Functions.forMap(mJapaneseToInteger);
    
            Map<Integer, String> mIntegerToSpanish = Maps.newHashMap();
            mIntegerToSpanish.put(1, "Uno");
            mIntegerToSpanish.put(3, "Tres");
            mIntegerToSpanish.put(4, "Cuatro");
            Function<Integer, String> integerToSpanish = Functions.forMap(mIntegerToSpanish);
    
            Function<String, String> japaneseToSpanish =
                    Functions.compose(integerToSpanish, japaneseToInteger);
    
            assertEquals("Uno", japaneseToSpanish.apply("Ichi"));
            try {
                japaneseToSpanish.apply("Ni");
                fail();
            } catch (IllegalArgumentException e) {
            }
            assertEquals("Tres", japaneseToSpanish.apply("San"));
            try {
                japaneseToSpanish.apply("Shi");
                fail();
            } catch (IllegalArgumentException e) {
            }
    
            new EqualsTester()
                    .addEqualityGroup(japaneseToSpanish, Functions.compose(integerToSpanish, japaneseToInteger))
                    .addEqualityGroup(japaneseToInteger)
                    .addEqualityGroup(integerToSpanish)
                    .addEqualityGroup(Functions.compose(japaneseToInteger, integerToSpanish))
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testComposition_includeReserializabled() {
            Map<String, Integer> mJapaneseToInteger = Maps.newHashMap();
            mJapaneseToInteger.put("Ichi", 1);
            mJapaneseToInteger.put("Ni", 2);
            mJapaneseToInteger.put("San", 3);
            Function<String, Integer> japaneseToInteger = Functions.forMap(mJapaneseToInteger);
    
            Map<Integer, String> mIntegerToSpanish = Maps.newHashMap();
            mIntegerToSpanish.put(1, "Uno");
            mIntegerToSpanish.put(3, "Tres");
            mIntegerToSpanish.put(4, "Cuatro");
            Function<Integer, String> integerToSpanish = Functions.forMap(mIntegerToSpanish);
    
            Function<String, String> japaneseToSpanish =
                    Functions.compose(integerToSpanish, japaneseToInteger);
    
            new EqualsTester()
                    .addEqualityGroup(
                            japaneseToSpanish,
                            Functions.compose(integerToSpanish, japaneseToInteger),
                            SerializableTester.reserialize(japaneseToSpanish))
                    .addEqualityGroup(japaneseToInteger)
                    .addEqualityGroup(integerToSpanish)
                    .addEqualityGroup(Functions.compose(japaneseToInteger, integerToSpanish))
                    .testEquals();
        }
    
        public void testCompositionWildcard() {
            Map<String, Integer> mapJapaneseToInteger = Maps.newHashMap();
            Function<String, Integer> japaneseToInteger = Functions.forMap(mapJapaneseToInteger);
    
            Function<Object, String> numberToSpanish = Functions.constant("Yo no se");
    
            Function<String, String> japaneseToSpanish =
                    Functions.compose(numberToSpanish, japaneseToInteger);
        }
    
        private static class HashCodeFunction implements Function<Object, Integer> {
            @Override
            public Integer apply(Object o) {
                return (o == null) ? 0 : o.hashCode();
            }
        }
    
        public void testComposeOfFunctionsIsAssociative() {
            Map<Float, String> m = ImmutableMap.of(4.0f, "A", 3.0f, "B", 2.0f, "C", 1.0f, "D");
            Function<? super Integer, Boolean> h = Functions.constant(Boolean.TRUE);
            Function<? super String, Integer> g = new HashCodeFunction();
            Function<Float, String> f = Functions.forMap(m, "F");
    
            Function<Float, Boolean> c1 = Functions.compose(Functions.compose(h, g), f);
            Function<Float, Boolean> c2 = Functions.compose(h, Functions.compose(g, f));
    
            // Might be nice (eventually) to have:
            //     assertEquals(c1, c2);
    
            // But for now, settle for this:
            assertEquals(c1.hashCode(), c2.hashCode());
    
            assertEquals(c1.apply(1.0f), c2.apply(1.0f));
            assertEquals(c1.apply(5.0f), c2.apply(5.0f));
        }
    
        public void testComposeOfPredicateAndFunctionIsAssociative() {
            Map<Float, String> m = ImmutableMap.of(4.0f, "A", 3.0f, "B", 2.0f, "C", 1.0f, "D");
            Predicate<? super Integer> h = Predicates.equalTo(42);
            Function<? super String, Integer> g = new HashCodeFunction();
            Function<Float, String> f = Functions.forMap(m, "F");
    
            Predicate<Float> p1 = Predicates.compose(Predicates.compose(h, g), f);
            Predicate<Float> p2 = Predicates.compose(h, Functions.compose(g, f));
    
            // Might be nice (eventually) to have:
            //     assertEquals(p1, p2);
    
            // But for now, settle for this:
            assertEquals(p1.hashCode(), p2.hashCode());
    
            assertEquals(p1.apply(1.0f), p2.apply(1.0f));
            assertEquals(p1.apply(5.0f), p2.apply(5.0f));
        }
    
        public void testForPredicate() {
            Function<Object, Boolean> alwaysTrue = Functions.forPredicate(Predicates.alwaysTrue());
            Function<Object, Boolean> alwaysFalse = Functions.forPredicate(Predicates.alwaysFalse());
    
            assertTrue(alwaysTrue.apply(0));
            assertFalse(alwaysFalse.apply(0));
    
            new EqualsTester()
                    .addEqualityGroup(alwaysTrue, Functions.forPredicate(Predicates.alwaysTrue()))
                    .addEqualityGroup(alwaysFalse)
                    .addEqualityGroup(Functions.identity())
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testForPredicateSerializable() {
            checkCanReserialize(Functions.forPredicate(Predicates.equalTo(5)));
        }
    
        public void testConstant() {
            Function<Object, Object> f = Functions.<Object>constant("correct");
            assertEquals("correct", f.apply(new Object()));
            assertEquals("correct", f.apply(null));
    
            Function<Object, String> g = Functions.constant(null);
            assertEquals(null, g.apply(2));
            assertEquals(null, g.apply(null));
    
            new EqualsTester()
                    .addEqualityGroup(f, Functions.constant("correct"))
                    .addEqualityGroup(Functions.constant("incorrect"))
                    .addEqualityGroup(Functions.toStringFunction())
                    .addEqualityGroup(g)
                    .testEquals();
    
            new EqualsTester()
                    .addEqualityGroup(g, Functions.constant(null))
                    .addEqualityGroup(Functions.constant("incorrect"))
                    .addEqualityGroup(Functions.toStringFunction())
                    .addEqualityGroup(f)
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testConstantSerializable() {
            checkCanReserialize(Functions.constant(5));
        }
    
        private static class CountingSupplier implements Supplier<Integer>, Serializable {
    
            private static final long serialVersionUID = 0;
    
            private int value;
    
            @Override
            public Integer get() {
                return ++value;
            }
    
            @Override
            public boolean equals(Object obj) {
                if (obj instanceof CountingSupplier) {
                    return this.value == ((CountingSupplier) obj).value;
                }
                return false;
            }
    
            @Override
            public int hashCode() {
                return value;
            }
        }
    
        public void testForSupplier() {
            Supplier<Integer> supplier = new CountingSupplier();
            Function<Object, Integer> function = Functions.forSupplier(supplier);
    
            assertEquals(1, (int) function.apply(null));
            assertEquals(2, (int) function.apply("foo"));
    
            new EqualsTester()
                    .addEqualityGroup(function, Functions.forSupplier(supplier))
                    .addEqualityGroup(Functions.forSupplier(new CountingSupplier()))
                    .addEqualityGroup(Functions.forSupplier(Suppliers.ofInstance(12)))
                    .addEqualityGroup(Functions.toStringFunction())
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testForSupplierSerializable() {
            checkCanReserialize(Functions.forSupplier(new CountingSupplier()));
        }
    
        @GwtIncompatible // reflection
        public void testNulls() throws Exception {
            new ClassSanityTester().forAllPublicStaticMethods(Functions.class).testNulls();
        }
    
        @GwtIncompatible // reflection
        // (I suspect that this and the other similar failures happen with ArbitraryInstances proxies.)
        public void testEqualsAndSerializable() throws Exception {
            new ClassSanityTester().forAllPublicStaticMethods(Functions.class).testEqualsAndSerializable();
        }
    
        @GwtIncompatible // SerializableTester
        private static <Y> void checkCanReserialize(Function<? super Integer, Y> f) {
            Function<? super Integer, Y> g = SerializableTester.reserializeAndAssert(f);
            for (int i = 1; i < 5; i++) {
                // convoluted way to check that the same result happens from each
                Y expected = null;
                try {
                    expected = f.apply(i);
                } catch (IllegalArgumentException e) {
                    try {
                        g.apply(i);
                        fail();
                    } catch (IllegalArgumentException ok) {
                        continue;
                    }
                }
                assertEquals(expected, g.apply(i));
            }
        }
    
        @GwtIncompatible // SerializableTester
        private static <Y> void checkCanReserializeSingleton(Function<? super String, Y> f) {
            Function<? super String, Y> g = SerializableTester.reserializeAndAssert(f);
            assertSame(f, g);
            for (Integer i = 1; i < 5; i++) {
                assertEquals(f.apply(i.toString()), g.apply(i.toString()));
            }
        }
    }

7.2Predicate

    import com.google.common.annotations.GwtIncompatible;
    import com.google.common.base.*;
    import com.google.common.collect.ImmutableSet;
    import com.google.common.testing.ClassSanityTester;
    import com.google.common.testing.EqualsTester;
    import com.google.common.testing.NullPointerTester;
    import com.google.common.testing.SerializableTester;
    import junit.framework.AssertionFailedError;
    import junit.framework.TestCase;
    import java.io.Serializable;
    import java.util.*;
    import java.util.regex.Pattern;
    
    import static com.google.common.base.CharMatcher.whitespace;
    import static com.google.common.collect.Lists.newArrayList;
    
    public class PredicatesTest extends TestCase {
    
        private static final Predicate<Integer> TRUE = Predicates.alwaysTrue();
        private static final Predicate<Integer> FALSE = Predicates.alwaysFalse();
        private static final Predicate<Integer> NEVER_REACHED =
                new Predicate<Integer>() {
                    @Override
                    public boolean apply(Integer i) {
                        throw new AssertionFailedError("This predicate should never have been evaluated");
                    }
                };
    
        /**
         * Instantiable predicate with reasonable hashCode() and equals() methods.
         */
        static class IsOdd implements Predicate<Integer>, Serializable {
            private static final long serialVersionUID = 0x150ddL;
    
            @Override
            public boolean apply(Integer i) {
                return (i.intValue() & 1) == 1;
            }
    
            @Override
            public int hashCode() {
                return 0x150dd;
            }
    
            @Override
            public boolean equals(Object obj) {
                return obj instanceof IsOdd;
            }
    
            @Override
            public String toString() {
                return "IsOdd";
            }
        }
    
        /**
         * Generates a new Predicate per call.
         *
         * <p>Creating a new Predicate each time helps catch cases where code is using {@code x == y}
         * instead of {@code x.equals(y)}.
         */
        private static IsOdd isOdd() {
            return new IsOdd();
        }
    
        /*
         * Tests for Predicates.alwaysTrue().
         */
    
        public void testAlwaysTrue_apply() {
            assertEvalsToTrue(Predicates.alwaysTrue());
        }
    
        public void testAlwaysTrue_equality() throws Exception {
            new EqualsTester()
                    .addEqualityGroup(TRUE, Predicates.alwaysTrue())
                    .addEqualityGroup(isOdd())
                    .addEqualityGroup(Predicates.alwaysFalse())
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testAlwaysTrue_serialization() {
            checkSerialization(Predicates.alwaysTrue());
        }
    
        /*
         * Tests for Predicates.alwaysFalse().
         */
    
        public void testAlwaysFalse_apply() throws Exception {
            assertEvalsToFalse(Predicates.alwaysFalse());
        }
    
        public void testAlwaysFalse_equality() throws Exception {
            new EqualsTester()
                    .addEqualityGroup(FALSE, Predicates.alwaysFalse())
                    .addEqualityGroup(isOdd())
                    .addEqualityGroup(Predicates.alwaysTrue())
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testAlwaysFalse_serialization() {
            checkSerialization(Predicates.alwaysFalse());
        }
    
        /*
         * Tests for Predicates.not(predicate).
         */
    
        public void testNot_apply() {
            assertEvalsToTrue(Predicates.not(FALSE));
            assertEvalsToFalse(Predicates.not(TRUE));
            assertEvalsLikeOdd(Predicates.not(Predicates.not(isOdd())));
        }
    
        public void testNot_equality() {
            new EqualsTester()
                    .addEqualityGroup(Predicates.not(isOdd()), Predicates.not(isOdd()))
                    .addEqualityGroup(Predicates.not(TRUE))
                    .addEqualityGroup(isOdd())
                    .testEquals();
        }
    
        public void testNot_equalityForNotOfKnownValues() {
            new EqualsTester()
                    .addEqualityGroup(TRUE, Predicates.alwaysTrue())
                    .addEqualityGroup(FALSE)
                    .addEqualityGroup(Predicates.not(TRUE))
                    .testEquals();
    
            new EqualsTester()
                    .addEqualityGroup(FALSE, Predicates.alwaysFalse())
                    .addEqualityGroup(TRUE)
                    .addEqualityGroup(Predicates.not(FALSE))
                    .testEquals();
    
            new EqualsTester()
                    .addEqualityGroup(Predicates.isNull(), Predicates.isNull())
                    .addEqualityGroup(Predicates.notNull())
                    .addEqualityGroup(Predicates.not(Predicates.isNull()))
                    .testEquals();
    
            new EqualsTester()
                    .addEqualityGroup(Predicates.notNull(), Predicates.notNull())
                    .addEqualityGroup(Predicates.isNull())
                    .addEqualityGroup(Predicates.not(Predicates.notNull()))
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testNot_serialization() {
            checkSerialization(Predicates.not(isOdd()));
        }
    
        /*
         * Tests for all the different flavors of Predicates.and().
         */
    
        @SuppressWarnings("unchecked") // varargs
        public void testAnd_applyNoArgs() {
            assertEvalsToTrue(Predicates.and());
        }
    
        @SuppressWarnings("unchecked") // varargs
        public void testAnd_equalityNoArgs() {
            new EqualsTester()
                    .addEqualityGroup(Predicates.and(), Predicates.and())
                    .addEqualityGroup(Predicates.and(FALSE))
                    .addEqualityGroup(Predicates.or())
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        @SuppressWarnings("unchecked") // varargs
        public void testAnd_serializationNoArgs() {
            checkSerialization(Predicates.and());
        }
    
        @SuppressWarnings("unchecked") // varargs
        public void testAnd_applyOneArg() {
            assertEvalsLikeOdd(Predicates.and(isOdd()));
        }
    
        @SuppressWarnings("unchecked") // varargs
        public void testAnd_equalityOneArg() {
            Object[] notEqualObjects = {Predicates.and(NEVER_REACHED, FALSE)};
            new EqualsTester()
                    .addEqualityGroup(Predicates.and(NEVER_REACHED), Predicates.and(NEVER_REACHED))
                    .addEqualityGroup(notEqualObjects)
                    .addEqualityGroup(Predicates.and(isOdd()))
                    .addEqualityGroup(Predicates.and())
                    .addEqualityGroup(Predicates.or(NEVER_REACHED))
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        @SuppressWarnings("unchecked") // varargs
        public void testAnd_serializationOneArg() {
            checkSerialization(Predicates.and(isOdd()));
        }
    
        public void testAnd_applyBinary() {
            assertEvalsLikeOdd(Predicates.and(isOdd(), TRUE));
            assertEvalsLikeOdd(Predicates.and(TRUE, isOdd()));
            assertEvalsToFalse(Predicates.and(FALSE, NEVER_REACHED));
        }
    
        @SuppressWarnings("unchecked") // varargs
        public void testAnd_equalityBinary() {
            new EqualsTester()
                    .addEqualityGroup(Predicates.and(TRUE, NEVER_REACHED), Predicates.and(TRUE, NEVER_REACHED))
                    .addEqualityGroup(Predicates.and(NEVER_REACHED, TRUE))
                    .addEqualityGroup(Predicates.and(TRUE))
                    .addEqualityGroup(Predicates.or(TRUE, NEVER_REACHED))
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testAnd_serializationBinary() {
            checkSerialization(Predicates.and(TRUE, isOdd()));
        }
    
        @SuppressWarnings("unchecked") // varargs
        public void testAnd_applyTernary() {
            assertEvalsLikeOdd(Predicates.and(isOdd(), TRUE, TRUE));
            assertEvalsLikeOdd(Predicates.and(TRUE, isOdd(), TRUE));
            assertEvalsLikeOdd(Predicates.and(TRUE, TRUE, isOdd()));
            assertEvalsToFalse(Predicates.and(TRUE, FALSE, NEVER_REACHED));
        }
    
        @SuppressWarnings("unchecked") // varargs
        public void testAnd_equalityTernary() {
            new EqualsTester()
                    .addEqualityGroup(
                            Predicates.and(TRUE, isOdd(), NEVER_REACHED),
                            Predicates.and(TRUE, isOdd(), NEVER_REACHED))
                    .addEqualityGroup(Predicates.and(isOdd(), NEVER_REACHED, TRUE))
                    .addEqualityGroup(Predicates.and(TRUE))
                    .addEqualityGroup(Predicates.or(TRUE, isOdd(), NEVER_REACHED))
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        @SuppressWarnings("unchecked") // varargs
        public void testAnd_serializationTernary() {
            checkSerialization(Predicates.and(TRUE, isOdd(), FALSE));
        }
    
        @SuppressWarnings("unchecked") // varargs
        public void testAnd_applyIterable() {
            Collection<Predicate<Integer>> empty = Arrays.asList();
            assertEvalsToTrue(Predicates.and(empty));
            assertEvalsLikeOdd(Predicates.and(Arrays.asList(isOdd())));
            assertEvalsLikeOdd(Predicates.and(Arrays.asList(TRUE, isOdd())));
            assertEvalsToFalse(Predicates.and(Arrays.asList(FALSE, NEVER_REACHED)));
        }
    
        @SuppressWarnings("unchecked") // varargs
        public void testAnd_equalityIterable() {
            new EqualsTester()
                    .addEqualityGroup(
                            Predicates.and(Arrays.asList(TRUE, NEVER_REACHED)),
                            Predicates.and(Arrays.asList(TRUE, NEVER_REACHED)),
                            Predicates.and(TRUE, NEVER_REACHED))
                    .addEqualityGroup(Predicates.and(FALSE, NEVER_REACHED))
                    .addEqualityGroup(Predicates.or(TRUE, NEVER_REACHED))
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        @SuppressWarnings("unchecked") // varargs
        public void testAnd_serializationIterable() {
            checkSerialization(Predicates.and(Arrays.asList(TRUE, FALSE)));
        }
    
        @SuppressWarnings("unchecked") // varargs
        public void testAnd_arrayDefensivelyCopied() {
            Predicate[] array = {Predicates.alwaysFalse()};
            Predicate<Object> predicate = Predicates.and(array);
            assertFalse(predicate.apply(1));
            array[0] = Predicates.alwaysTrue();
            assertFalse(predicate.apply(1));
        }
    
        public void testAnd_listDefensivelyCopied() {
            List<Predicate<Object>> list = newArrayList();
            Predicate<Object> predicate = Predicates.and(list);
            assertTrue(predicate.apply(1));
            list.add(Predicates.alwaysFalse());
            assertTrue(predicate.apply(1));
        }
    
        public void testAnd_iterableDefensivelyCopied() {
            final List<Predicate<Object>> list = newArrayList();
            Iterable<Predicate<Object>> iterable =
                    new Iterable<Predicate<Object>>() {
                        @Override
                        public Iterator<Predicate<Object>> iterator() {
                            return list.iterator();
                        }
                    };
            Predicate<Object> predicate = Predicates.and(iterable);
            assertTrue(predicate.apply(1));
            list.add(Predicates.alwaysFalse());
            assertTrue(predicate.apply(1));
        }
    
        /*
         * Tests for all the different flavors of Predicates.or().
         */
    
        @SuppressWarnings("unchecked") // varargs
        public void testOr_applyNoArgs() {
            assertEvalsToFalse(Predicates.or());
        }
    
        @SuppressWarnings("unchecked") // varargs
        public void testOr_equalityNoArgs() {
            new EqualsTester()
                    .addEqualityGroup(Predicates.or(), Predicates.or())
                    .addEqualityGroup(Predicates.or(TRUE))
                    .addEqualityGroup(Predicates.and())
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        @SuppressWarnings("unchecked") // varargs
        public void testOr_serializationNoArgs() {
            checkSerialization(Predicates.or());
        }
    
        @SuppressWarnings("unchecked") // varargs
        public void testOr_applyOneArg() {
            assertEvalsToTrue(Predicates.or(TRUE));
            assertEvalsToFalse(Predicates.or(FALSE));
        }
    
        @SuppressWarnings("unchecked") // varargs
        public void testOr_equalityOneArg() {
            new EqualsTester()
                    .addEqualityGroup(Predicates.or(NEVER_REACHED), Predicates.or(NEVER_REACHED))
                    .addEqualityGroup(Predicates.or(NEVER_REACHED, TRUE))
                    .addEqualityGroup(Predicates.or(TRUE))
                    .addEqualityGroup(Predicates.or())
                    .addEqualityGroup(Predicates.and(NEVER_REACHED))
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        @SuppressWarnings("unchecked") // varargs
        public void testOr_serializationOneArg() {
            checkSerialization(Predicates.or(isOdd()));
        }
    
        public void testOr_applyBinary() {
            Predicate<Integer> falseOrFalse = Predicates.or(FALSE, FALSE);
            Predicate<Integer> falseOrTrue = Predicates.or(FALSE, TRUE);
            Predicate<Integer> trueOrAnything = Predicates.or(TRUE, NEVER_REACHED);
    
            assertEvalsToFalse(falseOrFalse);
            assertEvalsToTrue(falseOrTrue);
            assertEvalsToTrue(trueOrAnything);
        }
    
        @SuppressWarnings("unchecked") // varargs
        public void testOr_equalityBinary() {
            new EqualsTester()
                    .addEqualityGroup(Predicates.or(FALSE, NEVER_REACHED), Predicates.or(FALSE, NEVER_REACHED))
                    .addEqualityGroup(Predicates.or(NEVER_REACHED, FALSE))
                    .addEqualityGroup(Predicates.or(TRUE))
                    .addEqualityGroup(Predicates.and(FALSE, NEVER_REACHED))
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testOr_serializationBinary() {
            checkSerialization(Predicates.or(isOdd(), TRUE));
        }
    
        @SuppressWarnings("unchecked") // varargs
        public void testOr_applyTernary() {
            assertEvalsLikeOdd(Predicates.or(isOdd(), FALSE, FALSE));
            assertEvalsLikeOdd(Predicates.or(FALSE, isOdd(), FALSE));
            assertEvalsLikeOdd(Predicates.or(FALSE, FALSE, isOdd()));
            assertEvalsToTrue(Predicates.or(FALSE, TRUE, NEVER_REACHED));
        }
    
        @SuppressWarnings("unchecked") // varargs
        public void testOr_equalityTernary() {
            new EqualsTester()
                    .addEqualityGroup(
                            Predicates.or(FALSE, NEVER_REACHED, TRUE), Predicates.or(FALSE, NEVER_REACHED, TRUE))
                    .addEqualityGroup(Predicates.or(TRUE, NEVER_REACHED, FALSE))
                    .addEqualityGroup(Predicates.or(TRUE))
                    .addEqualityGroup(Predicates.and(FALSE, NEVER_REACHED, TRUE))
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        @SuppressWarnings("unchecked") // varargs
        public void testOr_serializationTernary() {
            checkSerialization(Predicates.or(FALSE, isOdd(), TRUE));
        }
    
        @SuppressWarnings("unchecked") // varargs
        public void testOr_applyIterable() {
            Predicate<Integer> vacuouslyFalse = Predicates.or(Collections.<Predicate<Integer>>emptyList());
            Predicate<Integer> troo = Predicates.or(Collections.singletonList(TRUE));
            /*
             * newLinkedList() takes varargs. TRUE and FALSE are both instances of
             * Predicate<Integer>, so the call is safe.
             */
            Predicate<Integer> trueAndFalse = Predicates.or(Arrays.asList(TRUE, FALSE));
    
            assertEvalsToFalse(vacuouslyFalse);
            assertEvalsToTrue(troo);
            assertEvalsToTrue(trueAndFalse);
        }
    
        @SuppressWarnings("unchecked") // varargs
        public void testOr_equalityIterable() {
            new EqualsTester()
                    .addEqualityGroup(
                            Predicates.or(Arrays.asList(FALSE, NEVER_REACHED)),
                            Predicates.or(Arrays.asList(FALSE, NEVER_REACHED)),
                            Predicates.or(FALSE, NEVER_REACHED))
                    .addEqualityGroup(Predicates.or(TRUE, NEVER_REACHED))
                    .addEqualityGroup(Predicates.and(FALSE, NEVER_REACHED))
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        @SuppressWarnings("unchecked") // varargs
        public void testOr_serializationIterable() {
            Predicate<Integer> pre = Predicates.or(Arrays.asList(TRUE, FALSE));
            Predicate<Integer> post = SerializableTester.reserializeAndAssert(pre);
            assertEquals(pre.apply(0), post.apply(0));
        }
    
        @SuppressWarnings("unchecked") // varargs
        public void testOr_arrayDefensivelyCopied() {
            Predicate[] array = {Predicates.alwaysFalse()};
            Predicate<Object> predicate = Predicates.or(array);
            assertFalse(predicate.apply(1));
            array[0] = Predicates.alwaysTrue();
            assertFalse(predicate.apply(1));
        }
    
        public void testOr_listDefensivelyCopied() {
            List<Predicate<Object>> list = newArrayList();
            Predicate<Object> predicate = Predicates.or(list);
            assertFalse(predicate.apply(1));
            list.add(Predicates.alwaysTrue());
            assertFalse(predicate.apply(1));
        }
    
        public void testOr_iterableDefensivelyCopied() {
            final List<Predicate<Object>> list = newArrayList();
            Iterable<Predicate<Object>> iterable =
                    new Iterable<Predicate<Object>>() {
                        @Override
                        public Iterator<Predicate<Object>> iterator() {
                            return list.iterator();
                        }
                    };
            Predicate<Object> predicate = Predicates.or(iterable);
            assertFalse(predicate.apply(1));
            list.add(Predicates.alwaysTrue());
            assertFalse(predicate.apply(1));
        }
    
        /*
         * Tests for Predicates.equalTo(x).
         */
    
        public void testIsEqualTo_apply() {
            Predicate<Integer> isOne = Predicates.equalTo(1);
    
            assertTrue(isOne.apply(1));
            assertFalse(isOne.apply(2));
            assertFalse(isOne.apply(null));
        }
    
        public void testIsEqualTo_equality() {
            new EqualsTester()
                    .addEqualityGroup(Predicates.equalTo(1), Predicates.equalTo(1))
                    .addEqualityGroup(Predicates.equalTo(2))
                    .addEqualityGroup(Predicates.equalTo(null))
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testIsEqualTo_serialization() {
            checkSerialization(Predicates.equalTo(1));
        }
    
        public void testIsEqualToNull_apply() {
            Predicate<Integer> isNull = Predicates.equalTo(null);
            assertTrue(isNull.apply(null));
            assertFalse(isNull.apply(1));
        }
    
        public void testIsEqualToNull_equality() {
            new EqualsTester()
                    .addEqualityGroup(Predicates.equalTo(null), Predicates.equalTo(null))
                    .addEqualityGroup(Predicates.equalTo(1))
                    .addEqualityGroup(Predicates.equalTo("null"))
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testIsEqualToNull_serialization() {
            checkSerialization(Predicates.equalTo(null));
        }
    
        /**
         * Tests for Predicates.instanceOf(x). TODO: Fix the comment style after fixing annotation
         * stripper to remove comments properly. Currently, all tests before the comments are removed as
         * well.
         */
        @GwtIncompatible // Predicates.instanceOf
        public void testIsInstanceOf_apply() {
            Predicate<Object> isInteger = Predicates.instanceOf(Integer.class);
    
            assertTrue(isInteger.apply(1));
            assertFalse(isInteger.apply(2.0f));
            assertFalse(isInteger.apply(""));
            assertFalse(isInteger.apply(null));
        }
    
        @GwtIncompatible // Predicates.instanceOf
        public void testIsInstanceOf_subclass() {
            Predicate<Object> isNumber = Predicates.instanceOf(Number.class);
    
            assertTrue(isNumber.apply(1));
            assertTrue(isNumber.apply(2.0f));
            assertFalse(isNumber.apply(""));
            assertFalse(isNumber.apply(null));
        }
    
        @GwtIncompatible // Predicates.instanceOf
        public void testIsInstanceOf_interface() {
            Predicate<Object> isComparable = Predicates.instanceOf(Comparable.class);
    
            assertTrue(isComparable.apply(1));
            assertTrue(isComparable.apply(2.0f));
            assertTrue(isComparable.apply(""));
            assertFalse(isComparable.apply(null));
        }
    
        @GwtIncompatible // Predicates.instanceOf
        public void testIsInstanceOf_equality() {
            new EqualsTester()
                    .addEqualityGroup(
                            Predicates.instanceOf(Integer.class), Predicates.instanceOf(Integer.class))
                    .addEqualityGroup(Predicates.instanceOf(Number.class))
                    .addEqualityGroup(Predicates.instanceOf(Float.class))
                    .testEquals();
        }
    
        @GwtIncompatible // Predicates.instanceOf, SerializableTester
        public void testIsInstanceOf_serialization() {
            checkSerialization(Predicates.instanceOf(Integer.class));
        }
    
        @GwtIncompatible // Predicates.subtypeOf
        public void testSubtypeOf_apply() {
            Predicate<Class<?>> isInteger = Predicates.subtypeOf(Integer.class);
    
            assertTrue(isInteger.apply(Integer.class));
            assertFalse(isInteger.apply(Float.class));
    
            try {
                isInteger.apply(null);
                fail();
            } catch (NullPointerException expected) {
            }
        }
    
        @GwtIncompatible // Predicates.subtypeOf
        public void testSubtypeOf_subclass() {
            Predicate<Class<?>> isNumber = Predicates.subtypeOf(Number.class);
    
            assertTrue(isNumber.apply(Integer.class));
            assertTrue(isNumber.apply(Float.class));
        }
    
        @GwtIncompatible // Predicates.subtypeOf
        public void testSubtypeOf_interface() {
            Predicate<Class<?>> isComparable = Predicates.subtypeOf(Comparable.class);
    
            assertTrue(isComparable.apply(Integer.class));
            assertTrue(isComparable.apply(Float.class));
        }
    
        @GwtIncompatible // Predicates.subtypeOf
        public void testSubtypeOf_equality() {
            new EqualsTester()
                    .addEqualityGroup(Predicates.subtypeOf(Integer.class))
                    .addEqualityGroup(Predicates.subtypeOf(Number.class))
                    .addEqualityGroup(Predicates.subtypeOf(Float.class))
                    .testEquals();
        }
    
        @GwtIncompatible // Predicates.subtypeOf, SerializableTester
        public void testSubtypeOf_serialization() {
            Predicate<Class<?>> predicate = Predicates.subtypeOf(Integer.class);
            Predicate<Class<?>> reserialized = SerializableTester.reserializeAndAssert(predicate);
    
            assertEvalsLike(predicate, reserialized, Integer.class);
            assertEvalsLike(predicate, reserialized, Float.class);
            assertEvalsLike(predicate, reserialized, null);
        }
    
        /*
         * Tests for Predicates.isNull()
         */
    
        public void testIsNull_apply() {
            Predicate<Integer> isNull = Predicates.isNull();
            assertTrue(isNull.apply(null));
            assertFalse(isNull.apply(1));
        }
    
        public void testIsNull_equality() {
            new EqualsTester()
                    .addEqualityGroup(Predicates.isNull(), Predicates.isNull())
                    .addEqualityGroup(Predicates.notNull())
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testIsNull_serialization() {
            Predicate<String> pre = Predicates.isNull();
            Predicate<String> post = SerializableTester.reserializeAndAssert(pre);
            assertEquals(pre.apply("foo"), post.apply("foo"));
            assertEquals(pre.apply(null), post.apply(null));
        }
    
        public void testNotNull_apply() {
            Predicate<Integer> notNull = Predicates.notNull();
            assertFalse(notNull.apply(null));
            assertTrue(notNull.apply(1));
        }
    
        public void testNotNull_equality() {
            new EqualsTester()
                    .addEqualityGroup(Predicates.notNull(), Predicates.notNull())
                    .addEqualityGroup(Predicates.isNull())
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testNotNull_serialization() {
            checkSerialization(Predicates.notNull());
        }
    
        public void testIn_apply() {
            Collection<Integer> nums = Arrays.asList(1, 5);
            Predicate<Integer> isOneOrFive = Predicates.in(nums);
    
            assertTrue(isOneOrFive.apply(1));
            assertTrue(isOneOrFive.apply(5));
            assertFalse(isOneOrFive.apply(3));
            assertFalse(isOneOrFive.apply(null));
        }
    
        public void testIn_equality() {
            Collection<Integer> nums = ImmutableSet.of(1, 5);
            Collection<Integer> sameOrder = ImmutableSet.of(1, 5);
            Collection<Integer> differentOrder = ImmutableSet.of(5, 1);
            Collection<Integer> differentNums = ImmutableSet.of(1, 3, 5);
    
            new EqualsTester()
                    .addEqualityGroup(
                            Predicates.in(nums),
                            Predicates.in(nums),
                            Predicates.in(sameOrder),
                            Predicates.in(differentOrder))
                    .addEqualityGroup(Predicates.in(differentNums))
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testIn_serialization() {
            checkSerialization(Predicates.in(Arrays.asList(1, 2, 3, null)));
        }
    
        public void testIn_handlesNullPointerException() {
            class CollectionThatThrowsNPE<T> extends ArrayList<T> {
                private static final long serialVersionUID = 1L;
    
                @Override
                public boolean contains(Object element) {
                    Preconditions.checkNotNull(element);
                    return super.contains(element);
                }
            }
            Collection<Integer> nums = new CollectionThatThrowsNPE<>();
            Predicate<Integer> isFalse = Predicates.in(nums);
            assertFalse(isFalse.apply(null));
        }
    
        public void testIn_handlesClassCastException() {
            class CollectionThatThrowsCCE<T> extends ArrayList<T> {
                private static final long serialVersionUID = 1L;
    
                @Override
                public boolean contains(Object element) {
                    throw new ClassCastException("");
                }
            }
            Collection<Integer> nums = new CollectionThatThrowsCCE<>();
            nums.add(3);
            Predicate<Integer> isThree = Predicates.in(nums);
            assertFalse(isThree.apply(3));
        }
    
        /*
         * Tests that compilation will work when applying explicit types.
         */
        @SuppressWarnings("unused") // compilation test
        public void testIn_compilesWithExplicitSupertype() {
            Collection<Number> nums = ImmutableSet.of();
            Predicate<Number> p1 = Predicates.in(nums);
            Predicate<Object> p2 = Predicates.<Object>in(nums);
            // The next two lines are not expected to compile.
            // Predicate<Integer> p3 = Predicates.in(nums);
            // Predicate<Integer> p4 = Predicates.<Integer>in(nums);
        }
    
        @GwtIncompatible // NullPointerTester
        public void testNullPointerExceptions() {
            NullPointerTester tester = new NullPointerTester();
            tester.testAllPublicStaticMethods(Predicates.class);
        }
    
        @SuppressWarnings("unchecked") // varargs
        @GwtIncompatible // SerializbleTester
        public void testCascadingSerialization() throws Exception {
            // Eclipse says Predicate<Integer>; javac says Predicate<Object>.
            Predicate<? super Integer> nasty =
                    Predicates.not(
                            Predicates.and(
                                    Predicates.or(
                                            Predicates.equalTo((Object) 1),
                                            Predicates.equalTo(null),
                                            Predicates.alwaysFalse(),
                                            Predicates.alwaysTrue(),
                                            Predicates.isNull(),
                                            Predicates.notNull(),
                                            Predicates.in(Arrays.asList(1)))));
            assertEvalsToFalse(nasty);
    
            Predicate<? super Integer> stillNasty = SerializableTester.reserializeAndAssert(nasty);
    
            assertEvalsToFalse(stillNasty);
        }
    
        // enum singleton pattern
        private enum TrimStringFunction implements Function<String, String> {
            INSTANCE;
    
            @Override
            public String apply(String string) {
                return whitespace().trimFrom(string);
            }
        }
    
        public void testCompose() {
            Function<String, String> trim = TrimStringFunction.INSTANCE;
            Predicate<String> equalsFoo = Predicates.equalTo("Foo");
            Predicate<String> equalsBar = Predicates.equalTo("Bar");
            Predicate<String> trimEqualsFoo = Predicates.compose(equalsFoo, trim);
            Function<String, String> identity = Functions.identity();
    
            assertTrue(trimEqualsFoo.apply("Foo"));
            assertTrue(trimEqualsFoo.apply("   Foo   "));
            assertFalse(trimEqualsFoo.apply("Foo-b-que"));
    
            new EqualsTester()
                    .addEqualityGroup(trimEqualsFoo, Predicates.compose(equalsFoo, trim))
                    .addEqualityGroup(equalsFoo)
                    .addEqualityGroup(trim)
                    .addEqualityGroup(Predicates.compose(equalsFoo, identity))
                    .addEqualityGroup(Predicates.compose(equalsBar, trim))
                    .testEquals();
        }
    
        @GwtIncompatible // SerializableTester
        public void testComposeSerialization() {
            Function<String, String> trim = TrimStringFunction.INSTANCE;
            Predicate<String> equalsFoo = Predicates.equalTo("Foo");
            Predicate<String> trimEqualsFoo = Predicates.compose(equalsFoo, trim);
            SerializableTester.reserializeAndAssert(trimEqualsFoo);
        }
    
        /**
         * Tests for Predicates.contains(Pattern) and .containsPattern(String). We assume the regex level
         * works, so there are only trivial tests of that aspect. TODO: Fix comment style once annotation
         * stripper is fixed.
         */
        @GwtIncompatible // Predicates.containsPattern
        public void testContainsPattern_apply() {
            Predicate<CharSequence> isFoobar = Predicates.containsPattern("^Fo.*o.*bar$");
            assertTrue(isFoobar.apply("Foxyzoabcbar"));
            assertFalse(isFoobar.apply("Foobarx"));
        }
    
        @GwtIncompatible // Predicates.containsPattern
        public void testContains_apply() {
            Predicate<CharSequence> isFoobar = Predicates.contains(Pattern.compile("^Fo.*o.*bar$"));
    
            assertTrue(isFoobar.apply("Foxyzoabcbar"));
            assertFalse(isFoobar.apply("Foobarx"));
        }
    
        @GwtIncompatible // NullPointerTester
        public void testContainsPattern_nulls() throws Exception {
            NullPointerTester tester = new NullPointerTester();
            Predicate<CharSequence> isWooString = Predicates.containsPattern("Woo");
    
            tester.testAllPublicInstanceMethods(isWooString);
        }
    
        @GwtIncompatible // NullPointerTester
        public void testContains_nulls() throws Exception {
            NullPointerTester tester = new NullPointerTester();
            Predicate<CharSequence> isWooPattern = Predicates.contains(Pattern.compile("Woo"));
    
            tester.testAllPublicInstanceMethods(isWooPattern);
        }
    
        @GwtIncompatible // SerializableTester
        public void testContainsPattern_serialization() {
            Predicate<CharSequence> pre = Predicates.containsPattern("foo");
            Predicate<CharSequence> post = SerializableTester.reserializeAndAssert(pre);
            assertEquals(pre.apply("foo"), post.apply("foo"));
        }
    
        @GwtIncompatible // java.util.regex.Pattern
        public void testContains_equals() {
            new EqualsTester()
                    .addEqualityGroup(
                            Predicates.contains(Pattern.compile("foo")), Predicates.containsPattern("foo"))
                    .addEqualityGroup(Predicates.contains(Pattern.compile("foo", Pattern.CASE_INSENSITIVE)))
                    .addEqualityGroup(Predicates.containsPattern("bar"))
                    .testEquals();
        }
    
        public void assertEqualHashCode(
                Predicate<? super Integer> expected, Predicate<? super Integer> actual) {
            assertEquals(actual + " should hash like " + expected, expected.hashCode(), actual.hashCode());
        }
    
        public void testHashCodeForBooleanOperations() {
            Predicate<Integer> p1 = Predicates.isNull();
            Predicate<Integer> p2 = isOdd();
    
            // Make sure that hash codes are not computed per-instance.
            assertEqualHashCode(Predicates.not(p1), Predicates.not(p1));
    
            assertEqualHashCode(Predicates.and(p1, p2), Predicates.and(p1, p2));
    
            assertEqualHashCode(Predicates.or(p1, p2), Predicates.or(p1, p2));
    
            // While not a contractual requirement, we'd like the hash codes for ands
            // & ors of the same predicates to not collide.
            assertTrue(Predicates.and(p1, p2).hashCode() != Predicates.or(p1, p2).hashCode());
        }
    
        @GwtIncompatible // reflection
        public void testNulls() throws Exception {
            new ClassSanityTester().forAllPublicStaticMethods(Predicates.class).testNulls();
        }
    
        @GwtIncompatible // reflection
        public void testEqualsAndSerializable() throws Exception {
            new ClassSanityTester().forAllPublicStaticMethods(Predicates.class).testEqualsAndSerializable();
        }
    
        private static void assertEvalsToTrue(Predicate<? super Integer> predicate) {
            assertTrue(predicate.apply(0));
            assertTrue(predicate.apply(1));
            assertTrue(predicate.apply(null));
        }
    
        private static void assertEvalsToFalse(Predicate<? super Integer> predicate) {
            assertFalse(predicate.apply(0));
            assertFalse(predicate.apply(1));
            assertFalse(predicate.apply(null));
        }
    
        private static void assertEvalsLikeOdd(Predicate<? super Integer> predicate) {
            assertEvalsLike(isOdd(), predicate);
        }
    
        private static void assertEvalsLike(
                Predicate<? super Integer> expected, Predicate<? super Integer> actual) {
            assertEvalsLike(expected, actual, 0);
            assertEvalsLike(expected, actual, 1);
            assertEvalsLike(expected, actual, null);
        }
    
        private static <T> void assertEvalsLike(
                Predicate<? super T> expected, Predicate<? super T> actual, T input) {
            Boolean expectedResult = null;
            RuntimeException expectedRuntimeException = null;
            try {
                expectedResult = expected.apply(input);
            } catch (RuntimeException e) {
                expectedRuntimeException = e;
            }
    
            Boolean actualResult = null;
            RuntimeException actualRuntimeException = null;
            try {
                actualResult = actual.apply(input);
            } catch (RuntimeException e) {
                actualRuntimeException = e;
            }
    
            assertEquals(expectedResult, actualResult);
            if (expectedRuntimeException != null) {
                assertNotNull(actualRuntimeException);
                assertEquals(expectedRuntimeException.getClass(), actualRuntimeException.getClass());
            }
        }
    
        @GwtIncompatible // SerializableTester
        private static void checkSerialization(Predicate<? super Integer> predicate) {
            Predicate<? super Integer> reserialized = SerializableTester.reserializeAndAssert(predicate);
            assertEvalsLike(predicate, reserialized);
        }
    }

7.3Equivalence

    import com.google.common.annotations.GwtIncompatible;
    import com.google.common.base.Equivalence;
    import com.google.common.base.Equivalence.Wrapper;
    import com.google.common.base.Function;
    import com.google.common.base.Functions;
    import com.google.common.base.Predicate;
    import com.google.common.collect.ImmutableList;
    import com.google.common.testing.EqualsTester;
    import com.google.common.testing.EquivalenceTester;
    import com.google.common.testing.NullPointerTester;
    import com.google.common.testing.SerializableTester;
    import junit.framework.TestCase;
    
    public class EquivalenceTest extends TestCase {
        
        @SuppressWarnings("unchecked") // varargs
        public void testPairwiseEquivalent() {
            EquivalenceTester.of(Equivalence.equals().<String>pairwise())
                    .addEquivalenceGroup(ImmutableList.<String>of())
                    .addEquivalenceGroup(ImmutableList.of("a"))
                    .addEquivalenceGroup(ImmutableList.of("b"))
                    .addEquivalenceGroup(ImmutableList.of("a", "b"), ImmutableList.of("a", "b"))
                    .test();
        }
    
        public void testPairwiseEquivalent_equals() {
            new EqualsTester()
                    .addEqualityGroup(Equivalence.equals().pairwise(), Equivalence.equals().pairwise())
                    .addEqualityGroup(Equivalence.identity().pairwise())
                    .testEquals();
        }
    
        private enum LengthFunction implements Function<String, Integer> {
            INSTANCE;
    
            @Override
            public Integer apply(String input) {
                return input.length();
            }
        }
    
        private static final Equivalence<String> LENGTH_EQUIVALENCE =
                Equivalence.equals().onResultOf(LengthFunction.INSTANCE);
    
        public void testWrap() {
            new EqualsTester()
                    .addEqualityGroup(
                            LENGTH_EQUIVALENCE.wrap("hello"),
                            LENGTH_EQUIVALENCE.wrap("hello"),
                            LENGTH_EQUIVALENCE.wrap("world"))
                    .addEqualityGroup(LENGTH_EQUIVALENCE.wrap("hi"), LENGTH_EQUIVALENCE.wrap("yo"))
                    .addEqualityGroup(LENGTH_EQUIVALENCE.wrap(null), LENGTH_EQUIVALENCE.wrap(null))
                    .addEqualityGroup(Equivalence.equals().wrap("hello"))
                    .addEqualityGroup(Equivalence.equals().wrap(null))
                    .testEquals();
        }
    
        public void testWrap_get() {
            String test = "test";
            Wrapper<String> wrapper = LENGTH_EQUIVALENCE.wrap(test);
            assertSame(test, wrapper.get());
        }
    
        @GwtIncompatible // SerializableTester
        public void testSerialization() {
            SerializableTester.reserializeAndAssert(LENGTH_EQUIVALENCE.wrap("hello"));
            SerializableTester.reserializeAndAssert(Equivalence.equals());
            SerializableTester.reserializeAndAssert(Equivalence.identity());
        }
    
        private static class IntValue {
            private final int value;
    
            IntValue(int value) {
                this.value = value;
            }
    
            @Override
            public String toString() {
                return "value = " + value;
            }
        }
    
        public void testOnResultOf() {
            EquivalenceTester.of(Equivalence.equals().onResultOf(Functions.toStringFunction()))
                    .addEquivalenceGroup(new IntValue(1), new IntValue(1))
                    .addEquivalenceGroup(new IntValue(2))
                    .test();
        }
    
        public void testOnResultOf_equals() {
            new EqualsTester()
                    .addEqualityGroup(
                            Equivalence.identity().onResultOf(Functions.toStringFunction()),
                            Equivalence.identity().onResultOf(Functions.toStringFunction()))
                    .addEqualityGroup(Equivalence.equals().onResultOf(Functions.toStringFunction()))
                    .addEqualityGroup(Equivalence.identity().onResultOf(Functions.identity()))
                    .testEquals();
        }
    
        public void testEquivalentTo() {
            Predicate<Object> equalTo1 = Equivalence.equals().equivalentTo("1");
            assertTrue(equalTo1.apply("1"));
            assertFalse(equalTo1.apply("2"));
            assertFalse(equalTo1.apply(null));
            Predicate<Object> isNull = Equivalence.equals().equivalentTo(null);
            assertFalse(isNull.apply("1"));
            assertFalse(isNull.apply("2"));
            assertTrue(isNull.apply(null));
    
            new EqualsTester()
                    .addEqualityGroup(equalTo1, Equivalence.equals().equivalentTo("1"))
                    .addEqualityGroup(isNull)
                    .addEqualityGroup(Equivalence.identity().equivalentTo("1"))
                    .testEquals();
        }
    
        public void testEqualsEquivalent() {
            EquivalenceTester.of(Equivalence.equals())
                    .addEquivalenceGroup(new Integer(42), 42)
                    .addEquivalenceGroup("a")
                    .test();
        }
    
        public void testIdentityEquivalent() {
            EquivalenceTester.of(Equivalence.identity())
                    .addEquivalenceGroup(new Integer(42))
                    .addEquivalenceGroup(new Integer(42))
                    .addEquivalenceGroup("a")
                    .test();
        }
    
        public void testEquals() {
            new EqualsTester()
                    .addEqualityGroup(Equivalence.equals(), Equivalence.equals())
                    .addEqualityGroup(Equivalence.identity(), Equivalence.identity())
                    .testEquals();
        }
    
        @GwtIncompatible // NullPointerTester
        public void testNulls() {
            new NullPointerTester().testAllPublicStaticMethods(Equivalence.class);
            new NullPointerTester().testAllPublicInstanceMethods(Equivalence.equals());
            new NullPointerTester().testAllPublicInstanceMethods(Equivalence.identity());
        }
    }

7.4Converter

    import com.google.common.base.Converter;
    import com.google.common.base.Function;
    import com.google.common.collect.ImmutableList;
    import com.google.common.collect.Lists;
    import com.google.common.primitives.Longs;
    import com.google.common.testing.EqualsTester;
    import com.google.common.testing.SerializableTester;
    import junit.framework.TestCase;
    import java.util.Iterator;
    import java.util.List;
    
    import static com.google.common.base.Functions.toStringFunction;
    
    public class ConverterTest extends TestCase {
    
        private static final Converter<String, Long> STR_TO_LONG =
                new Converter<String, Long>() {
                    @Override
                    protected Long doForward(String object) {
                        return Long.valueOf(object);
                    }
    
                    @Override
                    protected String doBackward(Long object) {
                        return String.valueOf(object);
                    }
    
                    @Override
                    public String toString() {
                        return "string2long";
                    }
                };
    
        private static final Long LONG_VAL = 12345L;
        private static final String STR_VAL = "12345";
    
        private static final ImmutableList<String> STRINGS = ImmutableList.of("123", "456");
        private static final ImmutableList<Long> LONGS = ImmutableList.of(123L, 456L);
    
        public void testConverter() {
            assertEquals(LONG_VAL, STR_TO_LONG.convert(STR_VAL));
            assertEquals(STR_VAL, STR_TO_LONG.reverse().convert(LONG_VAL));
    
            Iterable<Long> convertedValues = STR_TO_LONG.convertAll(STRINGS);
            assertEquals(LONGS, ImmutableList.copyOf(convertedValues));
        }
    
        public void testConvertAllIsView() {
            List<String> mutableList = Lists.newArrayList("789", "123");
            Iterable<Long> convertedValues = STR_TO_LONG.convertAll(mutableList);
            assertEquals(ImmutableList.of(789L, 123L), ImmutableList.copyOf(convertedValues));
    
            Iterator<Long> iterator = convertedValues.iterator();
            iterator.next();
            iterator.remove();
            assertEquals(ImmutableList.of("123"), mutableList);
        }
    
        public void testReverse() {
            Converter<Long, String> reverseConverter = STR_TO_LONG.reverse();
    
            assertEquals(STR_VAL, reverseConverter.convert(LONG_VAL));
            assertEquals(LONG_VAL, reverseConverter.reverse().convert(STR_VAL));
    
            Iterable<String> convertedValues = reverseConverter.convertAll(LONGS);
            assertEquals(STRINGS, ImmutableList.copyOf(convertedValues));
    
            assertSame(STR_TO_LONG, reverseConverter.reverse());
    
            assertEquals("string2long.reverse()", reverseConverter.toString());
    
            new EqualsTester()
                    .addEqualityGroup(STR_TO_LONG, STR_TO_LONG.reverse().reverse())
                    .addEqualityGroup(STR_TO_LONG.reverse(), STR_TO_LONG.reverse())
                    .testEquals();
        }
    
        public void testReverseReverse() {
            Converter<String, Long> converter = STR_TO_LONG;
            assertEquals(converter, converter.reverse().reverse());
        }
    
        public void testApply() {
            assertEquals(LONG_VAL, STR_TO_LONG.apply(STR_VAL));
        }
    
        private static class StringWrapper {
            private final String value;
    
            public StringWrapper(String value) {
                this.value = value;
            }
        }
    
        public void testAndThen() {
            Converter<StringWrapper, String> first =
                    new Converter<StringWrapper, String>() {
                        @Override
                        protected String doForward(StringWrapper object) {
                            return object.value;
                        }
    
                        @Override
                        protected StringWrapper doBackward(String object) {
                            return new StringWrapper(object);
                        }
    
                        @Override
                        public String toString() {
                            return "StringWrapper";
                        }
                    };
    
            Converter<StringWrapper, Long> converter = first.andThen(STR_TO_LONG);
    
            assertEquals(LONG_VAL, converter.convert(new StringWrapper(STR_VAL)));
            assertEquals(STR_VAL, converter.reverse().convert(LONG_VAL).value);
    
            assertEquals("StringWrapper.andThen(string2long)", converter.toString());
    
            assertEquals(first.andThen(STR_TO_LONG), first.andThen(STR_TO_LONG));
        }
    
        public void testIdentityConverter() {
            Converter<String, String> stringIdentityConverter = Converter.identity();
    
            assertSame(stringIdentityConverter, stringIdentityConverter.reverse());
            assertSame(STR_TO_LONG, stringIdentityConverter.andThen(STR_TO_LONG));
    
            assertSame(STR_VAL, stringIdentityConverter.convert(STR_VAL));
            assertSame(STR_VAL, stringIdentityConverter.reverse().convert(STR_VAL));
    
            assertEquals("Converter.identity()", stringIdentityConverter.toString());
    
            assertSame(Converter.identity(), Converter.identity());
        }
    
        public void testFrom() {
            Function<String, Integer> forward =
                    new Function<String, Integer>() {
                        @Override
                        public Integer apply(String input) {
                            return Integer.parseInt(input);
                        }
                    };
            Function<Object, String> backward = toStringFunction();
    
            Converter<String, Number> converter = Converter.<String, Number>from(forward, backward);
    
            assertNull(converter.convert(null));
            assertNull(converter.reverse().convert(null));
    
            assertEquals((Integer) 5, converter.convert("5"));
            assertEquals("5", converter.reverse().convert(5));
        }
    
        public void testSerialization_identity() {
            Converter<String, String> identityConverter = Converter.identity();
            SerializableTester.reserializeAndAssert(identityConverter);
        }
    
        public void testSerialization_reverse() {
            Converter<Long, String> reverseConverter = Longs.stringConverter().reverse();
            SerializableTester.reserializeAndAssert(reverseConverter);
        }
    
        public void testSerialization_andThen() {
            Converter<String, Long> converterA = Longs.stringConverter();
            Converter<Long, String> reverseConverter = Longs.stringConverter().reverse();
            Converter<String, String> composedConverter = converterA.andThen(reverseConverter);
            SerializableTester.reserializeAndAssert(composedConverter);
        }
    
        public void testSerialization_from() {
            Converter<String, String> dumb = Converter.from(toStringFunction(), toStringFunction());
            SerializableTester.reserializeAndAssert(dumb);
        }
    
    }

7.5Supplier

    import com.google.common.annotations.GwtIncompatible;
    import com.google.common.base.Function;
    import com.google.common.base.Functions;
    import com.google.common.base.Supplier;
    import com.google.common.base.Suppliers;
    import com.google.common.collect.Lists;
    import com.google.common.testing.ClassSanityTester;
    import com.google.common.testing.EqualsTester;
    import junit.framework.TestCase;
    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.TimeoutException;
    import java.util.concurrent.atomic.AtomicInteger;
    import java.util.concurrent.atomic.AtomicReference;
    
    import static com.google.common.testing.SerializableTester.reserialize;
    import static com.google.common.truth.Truth.assertThat;
    
    public class SuppliersTest extends TestCase {
    
        static class CountingSupplier implements Supplier<Integer> {
            int calls = 0;
    
            @Override
            public Integer get() {
                calls++;
                return calls * 10;
            }
    
            @Override
            public String toString() {
                return "CountingSupplier";
            }
        }
    
        static class ThrowingSupplier implements Supplier<Integer> {
            @Override
            public Integer get() {
                throw new NullPointerException();
            }
        }
    
        static class SerializableCountingSupplier extends CountingSupplier implements Serializable {
            private static final long serialVersionUID = 0L;
        }
    
        static class SerializableThrowingSupplier extends ThrowingSupplier implements Serializable {
            private static final long serialVersionUID = 0L;
        }
    
        static void checkMemoize(CountingSupplier countingSupplier, Supplier<Integer> memoizedSupplier) {
            // the underlying supplier hasn't executed yet
            assertEquals(0, countingSupplier.calls);
    
            assertEquals(10, (int) memoizedSupplier.get());
    
            // now it has
            assertEquals(1, countingSupplier.calls);
    
            assertEquals(10, (int) memoizedSupplier.get());
    
            // it still should only have executed once due to memoization
            assertEquals(1, countingSupplier.calls);
        }
    
        public void testMemoize() {
            memoizeTest(new CountingSupplier());
            memoizeTest(new SerializableCountingSupplier());
        }
    
        private void memoizeTest(CountingSupplier countingSupplier) {
            Supplier<Integer> memoizedSupplier = Suppliers.memoize(countingSupplier);
            checkMemoize(countingSupplier, memoizedSupplier);
        }
    
        public void testMemoize_redudantly() {
            memoize_redudantlyTest(new CountingSupplier());
            memoize_redudantlyTest(new SerializableCountingSupplier());
        }
    
        private void memoize_redudantlyTest(CountingSupplier countingSupplier) {
            Supplier<Integer> memoizedSupplier = Suppliers.memoize(countingSupplier);
            assertSame(memoizedSupplier, Suppliers.memoize(memoizedSupplier));
        }
    
        public void testMemoizeExceptionThrown() {
            memoizeExceptionThrownTest(new ThrowingSupplier());
            memoizeExceptionThrownTest(new SerializableThrowingSupplier());
        }
    
        private void memoizeExceptionThrownTest(ThrowingSupplier throwingSupplier) {
            Supplier<Integer> memoizedSupplier = Suppliers.memoize(throwingSupplier);
            // call get() twice to make sure that memoization doesn't interfere
            // with throwing the exception
            for (int i = 0; i < 2; i++) {
                try {
                    memoizedSupplier.get();
                    fail("failed to throw NullPointerException");
                } catch (NullPointerException e) {
                    // this is what should happen
                }
            }
        }
    
        @GwtIncompatible // SerializableTester
        public void testMemoizeNonSerializable() throws Exception {
            CountingSupplier countingSupplier = new CountingSupplier();
            Supplier<Integer> memoizedSupplier = Suppliers.memoize(countingSupplier);
            assertThat(memoizedSupplier.toString()).isEqualTo("Suppliers.memoize(CountingSupplier)");
            checkMemoize(countingSupplier, memoizedSupplier);
            // Calls to the original memoized supplier shouldn't affect its copy.
            memoizedSupplier.get();
            assertThat(memoizedSupplier.toString())
                    .isEqualTo("Suppliers.memoize(<supplier that returned 10>)");
    
            // Should get an exception when we try to serialize.
            try {
                reserialize(memoizedSupplier);
                fail();
            } catch (RuntimeException ex) {
                assertThat(ex).hasCauseThat().isInstanceOf(java.io.NotSerializableException.class);
            }
        }
    
        public void testCompose() {
            Supplier<Integer> fiveSupplier =
                    new Supplier<Integer>() {
                        @Override
                        public Integer get() {
                            return 5;
                        }
                    };
    
            Function<Number, Integer> intValueFunction =
                    new Function<Number, Integer>() {
                        @Override
                        public Integer apply(Number x) {
                            return x.intValue();
                        }
                    };
    
            Supplier<Integer> squareSupplier = Suppliers.compose(intValueFunction, fiveSupplier);
    
            assertEquals(Integer.valueOf(5), squareSupplier.get());
        }
    
        public void testComposeWithLists() {
            Supplier<ArrayList<Integer>> listSupplier =
                    new Supplier<ArrayList<Integer>>() {
                        @Override
                        public ArrayList<Integer> get() {
                            return Lists.newArrayList(0);
                        }
                    };
    
            Function<List<Integer>, List<Integer>> addElementFunction =
                    new Function<List<Integer>, List<Integer>>() {
                        @Override
                        public List<Integer> apply(List<Integer> list) {
                            ArrayList<Integer> result = Lists.newArrayList(list);
                            result.add(1);
                            return result;
                        }
                    };
    
            Supplier<List<Integer>> addSupplier = Suppliers.compose(addElementFunction, listSupplier);
    
            List<Integer> result = addSupplier.get();
            assertEquals(Integer.valueOf(0), result.get(0));
            assertEquals(Integer.valueOf(1), result.get(1));
        }
    
        @GwtIncompatible // Thread.sleep
        public void testMemoizeWithExpiration() throws InterruptedException {
            CountingSupplier countingSupplier = new CountingSupplier();
    
            Supplier<Integer> memoizedSupplier =
                    Suppliers.memoizeWithExpiration(countingSupplier, 75, TimeUnit.MILLISECONDS);
    
            checkExpiration(countingSupplier, memoizedSupplier);
        }
    
        @GwtIncompatible // Thread.sleep
        private void checkExpiration(
                CountingSupplier countingSupplier, Supplier<Integer> memoizedSupplier)
                throws InterruptedException {
            // the underlying supplier hasn't executed yet
            assertEquals(0, countingSupplier.calls);
    
            assertEquals(10, (int) memoizedSupplier.get());
            // now it has
            assertEquals(1, countingSupplier.calls);
    
            assertEquals(10, (int) memoizedSupplier.get());
            // it still should only have executed once due to memoization
            assertEquals(1, countingSupplier.calls);
    
            Thread.sleep(150);
    
            assertEquals(20, (int) memoizedSupplier.get());
            // old value expired
            assertEquals(2, countingSupplier.calls);
    
            assertEquals(20, (int) memoizedSupplier.get());
            // it still should only have executed twice due to memoization
            assertEquals(2, countingSupplier.calls);
        }
    
        public void testOfInstanceSuppliesSameInstance() {
            Object toBeSupplied = new Object();
            Supplier<Object> objectSupplier = Suppliers.ofInstance(toBeSupplied);
            assertSame(toBeSupplied, objectSupplier.get());
            assertSame(toBeSupplied, objectSupplier.get()); // idempotent
        }
    
        public void testOfInstanceSuppliesNull() {
            Supplier<Integer> nullSupplier = Suppliers.ofInstance(null);
            assertNull(nullSupplier.get());
        }
    
        @GwtIncompatible // Thread
    
        public void testExpiringMemoizedSupplierThreadSafe() throws Throwable {
            Function<Supplier<Boolean>, Supplier<Boolean>> memoizer =
                    new Function<Supplier<Boolean>, Supplier<Boolean>>() {
                        @Override
                        public Supplier<Boolean> apply(Supplier<Boolean> supplier) {
                            return Suppliers.memoizeWithExpiration(supplier, Long.MAX_VALUE, TimeUnit.NANOSECONDS);
                        }
                    };
            testSupplierThreadSafe(memoizer);
        }
    
        @GwtIncompatible // Thread
    
        public void testMemoizedSupplierThreadSafe() throws Throwable {
            Function<Supplier<Boolean>, Supplier<Boolean>> memoizer =
                    new Function<Supplier<Boolean>, Supplier<Boolean>>() {
                        @Override
                        public Supplier<Boolean> apply(Supplier<Boolean> supplier) {
                            return Suppliers.memoize(supplier);
                        }
                    };
            testSupplierThreadSafe(memoizer);
        }
    
        @GwtIncompatible // Thread
        public void testSupplierThreadSafe(Function<Supplier<Boolean>, Supplier<Boolean>> memoizer)
                throws Throwable {
            final AtomicInteger count = new AtomicInteger(0);
            final AtomicReference<Throwable> thrown = new AtomicReference<>(null);
            final int numThreads = 3;
            final Thread[] threads = new Thread[numThreads];
            final long timeout = TimeUnit.SECONDS.toNanos(60);
    
            final Supplier<Boolean> supplier =
                    new Supplier<Boolean>() {
                        boolean isWaiting(Thread thread) {
                            switch (thread.getState()) {
                                case BLOCKED:
                                case WAITING:
                                case TIMED_WAITING:
                                    return true;
                                default:
                                    return false;
                            }
                        }
    
                        int waitingThreads() {
                            int waitingThreads = 0;
                            for (Thread thread : threads) {
                                if (isWaiting(thread)) {
                                    waitingThreads++;
                                }
                            }
                            return waitingThreads;
                        }
    
                        @Override
                        public Boolean get() {
                            // Check that this method is called exactly once, by the first
                            // thread to synchronize.
                            long t0 = System.nanoTime();
                            while (waitingThreads() != numThreads - 1) {
                                if (System.nanoTime() - t0 > timeout) {
                                    thrown.set(
                                            new TimeoutException(
                                                    "timed out waiting for other threads to block"
                                                            + " synchronizing on supplier"));
                                    break;
                                }
                                Thread.yield();
                            }
                            count.getAndIncrement();
                            return Boolean.TRUE;
                        }
                    };
    
            final Supplier<Boolean> memoizedSupplier = memoizer.apply(supplier);
    
            for (int i = 0; i < numThreads; i++) {
                threads[i] =
                        new Thread() {
                            @Override
                            public void run() {
                                assertSame(Boolean.TRUE, memoizedSupplier.get());
                            }
                        };
            }
            for (Thread t : threads) {
                t.start();
            }
            for (Thread t : threads) {
                t.join();
            }
    
            if (thrown.get() != null) {
                throw thrown.get();
            }
            assertEquals(1, count.get());
        }
    
        @GwtIncompatible // Thread
    
        public void testSynchronizedSupplierThreadSafe() throws InterruptedException {
            final Supplier<Integer> nonThreadSafe =
                    new Supplier<Integer>() {
                        int counter = 0;
    
                        @Override
                        public Integer get() {
                            int nextValue = counter + 1;
                            Thread.yield();
                            counter = nextValue;
                            return counter;
                        }
                    };
    
            final int numThreads = 10;
            final int iterations = 1000;
            Thread[] threads = new Thread[numThreads];
            for (int i = 0; i < numThreads; i++) {
                threads[i] =
                        new Thread() {
                            @Override
                            public void run() {
                                for (int j = 0; j < iterations; j++) {
                                    Suppliers.synchronizedSupplier(nonThreadSafe).get();
                                }
                            }
                        };
            }
            for (Thread t : threads) {
                t.start();
            }
            for (Thread t : threads) {
                t.join();
            }
    
            assertEquals(numThreads * iterations + 1, (int) nonThreadSafe.get());
        }
    
        public void testSupplierFunction() {
            Supplier<Integer> supplier = Suppliers.ofInstance(14);
            Function<Supplier<Integer>, Integer> supplierFunction = Suppliers.supplierFunction();
    
            assertEquals(14, (int) supplierFunction.apply(supplier));
        }
    
        @GwtIncompatible // SerializationTester
        public void testSerialization() {
            assertEquals(Integer.valueOf(5), reserialize(Suppliers.ofInstance(5)).get());
            assertEquals(
                    Integer.valueOf(5),
                    reserialize(Suppliers.compose(Functions.identity(), Suppliers.ofInstance(5))).get());
            assertEquals(Integer.valueOf(5), reserialize(Suppliers.memoize(Suppliers.ofInstance(5))).get());
            assertEquals(
                    Integer.valueOf(5),
                    reserialize(Suppliers.memoizeWithExpiration(Suppliers.ofInstance(5), 30, TimeUnit.SECONDS))
                            .get());
            assertEquals(
                    Integer.valueOf(5),
                    reserialize(Suppliers.synchronizedSupplier(Suppliers.ofInstance(5))).get());
        }
    
        @GwtIncompatible // reflection
        public void testSuppliersNullChecks() throws Exception {
            new ClassSanityTester().forAllPublicStaticMethods(Suppliers.class).testNulls();
        }
    
        @GwtIncompatible // reflection
        public void testSuppliersSerializable() throws Exception {
            new ClassSanityTester().forAllPublicStaticMethods(Suppliers.class).testSerializable();
        }
    
        public void testOfInstance_equals() {
            new EqualsTester()
                    .addEqualityGroup(Suppliers.ofInstance("foo"), Suppliers.ofInstance("foo"))
                    .addEqualityGroup(Suppliers.ofInstance("bar"))
                    .testEquals();
        }
    
        public void testCompose_equals() {
            new EqualsTester()
                    .addEqualityGroup(
                            Suppliers.compose(Functions.constant(1), Suppliers.ofInstance("foo")),
                            Suppliers.compose(Functions.constant(1), Suppliers.ofInstance("foo")))
                    .addEqualityGroup(Suppliers.compose(Functions.constant(2), Suppliers.ofInstance("foo")))
                    .addEqualityGroup(Suppliers.compose(Functions.constant(1), Suppliers.ofInstance("bar")))
                    .testEquals();
        }
    }

本文参考:
FunctionalExplained
guava-tests-base

阅读全文