1. Function<F, T> & Functions
2. Predicate<T> & Predicates
3. Supplier<T> & Suppliers
1. Function & Functions
1> Function
With Java in its current state, we don't have closures as they exist in other languages.
For now, Java's answer to closures is to use anonymous classes.
While an anonymous class functions effectively in the same way as a closure, the syntax can be bulky and when used too much, can make your code hard to follow and maintain.
@Test public void functionTest2() { String dateStr = new Function<Date, String>() { private final SimpleDateFormat dateFormat = new SimpleDateFormat( "dd/MM/YYYY"); public String apply(Date input) { return dateFormat.format(input); } }.apply(Calendar.getInstance().getTime()); logger.info(dateStr); }
public String formatDate(Date date) { return new SimpleDateFormat("dd/MM/YYYY").format(date); }
Now compare the previous example of the anonymous class implementing Function interface.
This final example is much easier to read.
However, if you have a collection of Date objects and need to obtain a list contains the string representations of those date, the Function interface could be a better approach.
2> Functions.forMap
public static <K, V> Function<K, V> forMap(Map<K, V> map); public static <K, V> Function<K, V> forMap(Map<K, ? extends V> map, @Nullable V defaultValue);
@Test public void functionsTest() { Map<String, State> map = Maps.newHashMap(); Function<String, State> stateLookUpFunction = Functions.forMap(map, new State("UN", "Unknown")); map.put("NY", new State("NY", "New York")); map.put("CA", new State("CA", "California")); map.put("LA", new State("LA", "Los Angeles")); State state = stateLookUpFunction.apply("NY"); logger.info(state); state = stateLookUpFunction.apply("MS"); logger.info(state); }
There is one caveat to using the Functions.forMap method.
The map returned by Functions.forMap will throw an IllegalArgumentException if the given key is not found in the map.
Functions.forMap(map); // throw IllegalArgumentException if cannot find key Functions.forMap(map, null); // return "null" if cannot find key Functions.forMap(map, defaultValue); // return "defaultValue" if cannot find key
By using a Function interface to perform the state lookups, you can easily change out the implementation.
When combining it with a Splitter object to create a map or when using some of the other methods for map creation in Guava collection package,
we are leveraging the power of Guava in our code.
3> Functions.compose
public static <A, B, C> Function<A, C> compose(Function<B, C> g, Function<A, ? extends B> f) { return new FunctionComposition<A, B, C>(g, f); } public FunctionComposition(Function<B, C> g, Function<A, ? extends B> f) { this.g = checkNotNull(g); this.f = checkNotNull(f); } @Override public C apply(@Nullable A a) { return g.apply(f.apply(a)); }
Return the composition of two functions. For f: A->B and g: B->C, composition is defined as the function h such that h(a) == g(f(a)) for each a.
@Test public void composeTest() { Map<String, State> map = Maps.newHashMap(); map.put("NY", new State("NY", "New York")); map.put("CA", new State("CA", "California")); map.put("LA", new State("LA", "Los Angeles")); Function<String, String> function = Functions.compose( new Function<State, String>() { public String apply(State input) { return input.getStateAddress(); } }, Functions.forMap(map, new State("UN", "Unknown"))); logger.info(function.apply("NY")); // "New York" logger.info(function.apply("DA")); // "Unknown" // Functions.forMap() returns Function<String, State> // Anonymous innner Function<State, String> // The composed Function<String, String> }
2. Predicate & Predicates
1> Predicate
The Predicate interface is a functional cousin to the Function interface.
public interface Predicate<T>{ boolean apply(T input) }
@Test public void applyTest() { String input = "Davy Jones"; boolean containsKeyWords = new Predicate<String>() { public boolean apply(String input) { return input.contains("Davy"); } }.apply(input); logger.info(containsKeyWords); }
2> Predicates.and
@Test public void andTest() { String str = "Davy Jones"; boolean containsKeyWords = Predicates.and(new Predicate<String>() { public boolean apply(String input) { return input.contains("Davy"); } }, new Predicate<String>() { public boolean apply(String input) { return input.contains("Cool"); } }).apply(str); logger.info(containsKeyWords); //false }
3> Predicates.or
@Test public void orTest() { String str = "Davy Jones"; boolean containsKeyWords = Predicates.or(new Predicate<String>() { public boolean apply(String input) { return input.contains("Davy"); } }, new Predicate<String>() { public boolean apply(String input) { return input.contains("Cool"); } }).apply(str); logger.info(containsKeyWords); //true }
4> Predicates.not
@Test public void notTest() { String str = "Davy Jones"; boolean containsKeyWords = Predicates.not(new Predicate<String>() { public boolean apply(String input) { return input.contains("Davy"); } }).apply(str); logger.info(containsKeyWords); //false }
5> Predicates.compose
private CompositionPredicate(Predicate<B> p, Function<A, ? extends B> f) { this.p = checkNotNull(p); this.f = checkNotNull(f); } @Override public boolean apply(@Nullable A a) { return p.apply(f.apply(a)); }
@Test public void composeTest() { boolean isPersonMale = Predicates.compose(new Predicate<String>() { public boolean apply(String input) { return "Male".equals(input); } }, new Function<Person, String>() { public String apply(Person input) { return input.getGender(); } }).apply(new Person("Davy", "Male")); assertTrue(isPersonMale); } class Person { String name; String gender; public Person(String name, String gender) { super(); this.name = name; this.gender = gender; } public String getName() { return name; } public String getGender() { return gender; } }
3. Supplier & Suppliers
1> Supplier
public interface Supplier<T>{ T get(); }
The Supplier interface helps us implement several of the typical creational patterns.
When get is called, we would always return the same instance(singleton) or a new instance with each invocation.
@Test public void getTest() { String str = new Supplier<String>() { public String get() { return "AAA"; } }.get(); assertEquals("AAA", str); }
@Test public void getTest2() { Predicate<String> predicate = new Supplier<Predicate<String>>() { public Predicate<String> get() { return new Predicate<String>() { public boolean apply(String input) { return "AAA".equals(input); } }; } }.get(); assertTrue(predicate.apply("AAA")); assertFalse(predicate.apply("BBB")); }2> Suppliers.memoize
public static <T> Supplier<T> memoize(Supplier<T> delegate) { return (delegate instanceof MemoizingSupplier) ? delegate : new MemoizingSupplier<T>(Preconditions.checkNotNull(delegate)); } MemoizingSupplier(Supplier<T> delegate) { this.delegate = delegate; } @Override public T get() { // A 2-field variant of Double Checked Locking. if (!initialized) { synchronized (this) { if (!initialized) { T t = delegate.get(); value = t; initialized = true; return t; } } } return value; }
We can see from the source code that the MemoizingSupplier is just a proxy for innerSupplier, it stores an inner instance which is returned by delegate. Everytime we call get(), the proxy will return this instance.
@Test public void getTest() { Supplier<Object> supplier = new Supplier<Object>() { public Object get() { return new Object(); } }; Object obj1 = supplier.get(); Object obj2 = supplier.get(); assertNotEquals(obj1, obj2); Supplier<Object> proxy = Suppliers.memoize(supplier); obj1 = proxy.get(); obj2 = proxy.get(); assertEquals(obj1, obj2); }
3> Suppliers.memoizeWithExpiration
public static <T> Supplier<T> memoizeWithExpiration( Supplier<T> delegate, long duration, TimeUnit unit) { return new ExpiringMemoizingSupplier<T>(delegate, duration, unit); } ExpiringMemoizingSupplier( Supplier<T> delegate, long duration, TimeUnit unit) { this.delegate = Preconditions.checkNotNull(delegate); this.durationNanos = unit.toNanos(duration); Preconditions.checkArgument(duration > 0); } @Override public T get() { long nanos = expirationNanos; long now = Platform.systemNanoTime(); if (nanos == 0 || now - nanos >= 0) { synchronized (this) { if (nanos == expirationNanos) { // recheck for lost race T t = delegate.get(); value = t; nanos = now + durationNanos; expirationNanos = (nanos == 0) ? 1 : nanos; return t; } } } return value; }
@Test public void memoizeWithExpirationTest() throws InterruptedException { Supplier<Object> supplier = new Supplier<Object>() { public Object get() { return new Object(); } }; Object obj1 = supplier.get(); Object obj2 = supplier.get(); assertNotEquals(obj1, obj2); Supplier<Object> proxy = Suppliers.memoizeWithExpiration(supplier, 1L, TimeUnit.SECONDS); obj1 = proxy.get(); obj2 = proxy.get(); assertEquals(obj1, obj2); obj1 = proxy.get(); Thread.sleep(1000 * 2); obj2 = proxy.get(); assertNotEquals(obj1, obj2); }
4> Suppliers.compose
public static <F, T> Supplier<T> compose( Function<? super F, T> function, Supplier<F> supplier) { return new SupplierComposition<F, T>(function, supplier); } SupplierComposition(Function<? super F, T> function, Supplier<F> supplier) { this.function = function; this.supplier = supplier; } @Override public T get() { return function.apply(supplier.get()); }
@Test public void composeTest() { Map<String, String> map = Maps.newHashMap(); map.put("A", "A for alcohol"); map.put("B", "B for boycott"); Supplier<String> supplier = Suppliers.compose(Functions.forMap(map), new Supplier<String>() { public String get() { return "A"; } }); String str = supplier.get(); assertEquals("A for alcohol", str); }
Summary:
We've seen how Guava can add some functional aspects to Java with the Function and Predicate interfaces.
The Function interface provides us with the ability to transform objects and the Predicate interface gives us a powerful machanism for filtering.
The Functions and Predicates classes also help us write code that is easier to maintain and much easier to change.
The Suppliers help by providing essential collaborating objects while completely hiding the details of how those objects are created.
Combined with a dependency injection framework such as a Spring or Guice, these interfaces will allow us to seamlessly change the behavior of our programs by simply providing a different implementation.
Reference Links:
1) "Getting Started with Google Guava" -Bill Bejeck
相关推荐
Maven坐标:com.google.guava:guava:11.0.2; 标签:google、guava、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构...
Maven坐标:com.google.guava:guava:23.0; 标签:google、guava、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构...
Maven坐标:com.google.guava:guava:24.1-jre; 标签:google、guava、中英对照文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码...
Maven坐标:com.google.guava:guava:26.0-android; 标签:google、guava、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码...
Maven坐标:com.google.guava:guava:30.1.1-jre; 标签:google、guava、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和...
guava
最新版 guava-30.1-jre.jar
谷歌的Guava库是Java开发中的一个非常重要的开源项目,它提供了一系列的高效、实用的工具类,大大简化了常见的编程任务。Guava的核心特性包括集合框架、缓存、原生类型支持、并发库、字符串处理、I/O操作等。这个...
Guava是Google开发的一个核心库,它为Java平台提供了许多实用工具类,涵盖了集合、并发、I/O、字符串处理、数学运算等多个方面。这个压缩包包含的是Guava库的18.0版本,分为两个部分:`guava-18.0.jar`和`guava-18.0...
Guava是Google开发的一个核心库,它为Java平台提供了许多实用工具类,极大地丰富了标准库的功能。在Java开发中,Guava库被广泛使用,因为它包含了大量的集合框架、并发支持、缓存机制、字符串处理、I/O操作等多个...
Guava是Google开发的一个Java库,它包含许多Google核心库中的高级集合、缓存、原生类型支持、并发包、字符串处理、I/O等工具类。版本33.0.0是Guava的一个更新,提供了最新的功能改进和错误修复。在深入探讨Guava常用...
标题中的"guava-r09-jarjar.jar"是一个特定版本的Guava库,经过JarJar工具处理后的结果。Guava是Google的一个核心库,它提供了很多Java平台的基础工具,包括集合、缓存、原生类型支持、并发、函数式编程、字符串处理...
赠送jar包:guava-18.0.jar 赠送原API文档:guava-18.0-javadoc.jar 赠送源代码:guava-18.0-sources.jar 包含翻译后的API文档:guava-18.0-javadoc-API文档-中文(简体)-英语-对照版.zip 对应Maven信息:groupId...
Guava是Google开发的一个开源Java库,包含了众多的实用工具类和集合框架,极大地提高了Java开发的效率。在本例中,我们关注的是"guava-30.1-jre.jar",这是一个针对Java运行环境(JRE)优化的Guava版本,版本号为...
javaweb/javaee 常用jar包,亲测可用,若需其他版本其他jar包请留言我看到后会上传分享
google的guava工具包很实用,包括之前的字符串处理工具类的,还有大量的collection相关的
Guava: Google Core Libraries for Java Guava is a set of core libraries that includes new collection types (such as multimap and multiset), immutable collections, a graph library, functional types, ...
Maven坐标:com.google.guava:guava:20.0; 标签:google、guava、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构...
Maven坐标:com.google.guava:guava:17.0; 标签:google、guava、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构...
guava-18.0.jar 包中包含了所有com.google.common类