`
DavyJones2010
  • 浏览: 151837 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Guava: Functional Programming with Guava

阅读更多

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

 

分享到:
评论

相关推荐

    guava-11.0.2-API文档-中文版.zip

    Maven坐标:com.google.guava:guava:11.0.2; 标签:google、guava、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构...

    guava-23.0-API文档-中文版.zip

    Maven坐标:com.google.guava:guava:23.0; 标签:google、guava、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构...

    guava-26.0-android-API文档-中英对照版.zip

    Maven坐标:com.google.guava:guava:26.0-android; 标签:google、guava、jar包、java、中英对照文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的...

    guava-24.1-jre-API文档-中英对照版.zip

    Maven坐标:com.google.guava:guava:24.1-jre; 标签:google、guava、中英对照文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码...

    guava-26.0-android-API文档-中文版.zip

    Maven坐标:com.google.guava:guava:26.0-android; 标签:google、guava、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码...

    guava-30.1.1-jre-API文档-中文版.zip

    Maven坐标:com.google.guava:guava:30.1.1-jre; 标签:google、guava、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和...

    guava-18.0(guava-18.0.jar和guava-18.0-sources.jar)

    Guava是Google开发的一个核心库,它为Java平台提供了许多实用工具类,涵盖了集合、并发、I/O、字符串处理、数学运算等多个方面。这个压缩包包含的是Guava库的18.0版本,分为两个部分:`guava-18.0.jar`和`guava-18.0...

    guava-19.0 jar和sources

    Guava是Google开发的一个核心库,它为Java平台提供了许多实用工具类,极大地丰富了标准库的功能。在Java开发中,Guava库被广泛使用,因为它包含了大量的集合框架、并发支持、缓存机制、字符串处理、I/O操作等多个...

    guava-r09-jarjar.jar

    标题中的"guava-r09-jarjar.jar"是一个特定版本的Guava库,经过JarJar工具处理后的结果。Guava是Google的一个核心库,它提供了很多Java平台的基础工具,包括集合、缓存、原生类型支持、并发、函数式编程、字符串处理...

    guava-31.1-jre.jar

    guava

    guava-18.0-API文档-中英对照版.zip

    赠送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-30.1-jre.jar

    Guava是Google开发的一个开源Java库,包含了众多的实用工具类和集合框架,极大地提高了Java开发的效率。在本例中,我们关注的是"guava-30.1-jre.jar",这是一个针对Java运行环境(JRE)优化的Guava版本,版本号为...

    最新版 guava-30.1-jre.jar

    最新版 guava-30.1-jre.jar

    guava-32.1.3-android.jar

    javaweb/javaee 常用jar包,亲测可用,若需其他版本其他jar包请留言我看到后会上传分享

    guava-25.1-jre.jar

    google的guava工具包很实用,包括之前的字符串处理工具类的,还有大量的collection相关的

    Android代码-guava

    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, ...

    guava-20.0-API文档-中文版.zip

    Maven坐标:com.google.guava:guava:20.0; 标签:google、guava、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构...

    guava-18.0.jar

    guava-18.0.jar 包中包含了所有com.google.common类

    guava-17.0-API文档-中文版.zip

    Maven坐标:com.google.guava:guava:17.0; 标签:google、guava、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构...

    guava-27.0.1-jre-API文档-中文版.zip

    Maven坐标:com.google.guava:guava:27.0.1-jre; 标签:google、guava、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和...

Global site tag (gtag.js) - Google Analytics