介绍下Guava中比较重要的几个类:Function、Predicate、Supplier
以及对应的工具类:Functions、Predicates、Suppliers
Function
Function是一个接口,本质是用来做转换的。主要是用apply
方法把input
转换为另外一个对象。一般都是用匿名内部类的方式使用。源码如下:
public interface Function<F, T> {
T apply(@Nullable F input);
boolean equals(@Nullable Object object);
}
java目前不支持闭包(除了java8),对于闭包,java目前只能说用匿名类,但是内部类语法的代码量比较大,如果大量用匿名类会使得代码难以阅读和维护。如果了解javascript中的function对象和apply方法,会对guava的Function类的语义理解有很重要的帮助
Fucntion的一个转换实例
将日期型,转换为字符串
Function<Date, String> fun = new Function<Date, String>() {
public String apply(Date input) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(input);
}
};
String apply = fun.apply(new Date());
System.out.println(apply); //输出:2016-06-14 17:33:03
从上面的代码没看出来Function有啥好的地方,反而使得代码更复杂了。所以并不是所有的转换场景都适合用Function。一些简单原则是
- 能用简单的方法,就不要用Function
- 一般单一对象转换不需要用Function,针对集合的可以考虑使用
Function的集合实例
ArrayList<String> lists = Lists.newArrayList("a", "b", "c");
List<String> objects = FluentIterable.from(lists).transform(new Function<String, String>() {
public String apply(String input) {
return input + "-" + input;
}
}).toList();
System.out.println(objects);//输出[a,-a,, b-b, c-c]
使用FluentIterable.from(list).tranfrom(Function)
来转换真个集合的元素
Functions
Functions针对Function提供了一些工具类
compose
组合Function,比如Function1是把A转换为B,Function2是把B转换为C,可是用compose组合Function1和Function2,从而得到一个Function实例,把A转换为C。 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);
}
其中FunctionComposition
的apply
方法如下:只是组合调用了下两个Function,从而实现了A->B,B->C。最后能A->C
public C apply(A a) {
return g.apply(f.apply(a));
}
forMap
从一个map构建一个Function
HashMap<String, String> map = Maps.newHashMap();
map.put("a","11");
map.put("b","22");
Function<String, String> function = Functions.forMap(map);
System.out.println(function.apply("a"));
System.out.println(function.apply("c"));//如果key不存在就抛异常了
如果不希望key不存在抛出异常,可以用Functions.forMap(map,null)
来创建Function,指明key不存在的时候返回默认值:null
Predicate
Predicate是一个接口,本质是用来做过滤的。一般也是用作匿名内部类,源码如下
public interface Predicate<T>{
boolean apply(T input);
boolean equals(Object object);
}
Predicate和上面的Function 语法很相近,只是功能不一样,使用原则也和Function类似。
- Function 做转换用
- Predicate 做过滤用
Predicates
提供了针对Predicate的工具类
in
从list创建一个Predicate
ArrayList<String> lists = Lists.newArrayList("a", "b", "c");
Predicate<String> predicate = Predicates.in(lists);
predicate.apply("a");//true
predicate.apply("d");//false
and、or、not
可以使用and、or、not连接Predicate。形成复合条件的Predicate
//大于7
Predicate<Integer> greater7 = new Predicate<Integer>() {
public boolean apply(Integer input) {
return input > 7;
}
};
System.out.println(greater7.apply(2)); //输出:false
System.out.println(greater7.apply(8)); //输出:true
//小于3
Predicate<Integer> less3 = new Predicate<Integer>() {
public boolean apply(Integer input) {
return input < 3;
}
};
System.out.println(less3.apply(2));//输出:true
System.out.println(less3.apply(8));//输出:false
//大于7或小于3
Predicate<Integer> or = Predicates.or(greater7, less3);
System.out.println(or.apply(2));//输出:true
System.out.println(or.apply(8));//输出:true
compose
Predicate pre=Predicates.compose(Predicate,Function);
组合一个predicate和function,形成新的predicate,实际执行apply时候的过程如下所示:先用Function转换下入参a,然后应用到predicate
public boolean apply(A a) {
return predicate.apply(function.apply(a));
}
Supplier
Supplier是一个接口,用来帮助我们创建对象实例。借助Supplier可以实现创建型的设计模式,get方法抽象了创建对象的细节。源码如下:
public interface Supplier<T> {
T get();
}
具体用的时候就是实现Supplier接口实现自己的逻辑,这个接口是不是感觉没太大用途,除了在抽象的语义方面。如果结合Suppliers
就能看出来用途了。
Suppliers
提供了处理Supplier
的一些操作
memoize
可以实现单例,使用方法如下:
//定义一个Supplier,里面创建对象
Supplier<String> supp = new Supplier<String>() {
public String get() {
System.out.println("初始化对象。。。");
return "guava";
}
};
//得到一个创建单例对象的Supplier
Supplier<String> memoize = Suppliers.memoize(supp);
System.out.println(memoize.get());
System.out.println(memoize.get());
执行结果如下,调用了两次get,但只执行了一次对象初始化
初始化对象。。。
guava
guava
查看memoize的源码,可以看到使用的是双重校验加锁创建单例的方式:
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;
}
顺便提下java实现单例的有几种方式:
- 饿汉模式的声明初始化
private static final Type instance=new Type();
- 双重校验加锁
private volatile Type instance;
public static Type getInstance(){
if(instance==null){
synchronized (Type.class){
if(instance==null){
instance=new Type();
}
}
}
return instance;
}
- 内部类
public class Type{
private static class SingletonHelper{
private static final Type INSTANCE = new Type ();
}
public static Type getInstance(){
return SingletonHelper.INSTANCE;
}
}
- 枚举
public enum EnumSingleton {
//some 属性
INSTANCE;
public static void doSomething(){
//do something
}
}
memoizeWithExpiration
提供了获取单例功能的同时增加了超时失效重新获取的功能呢。Suppliers.memoizeWithExpiration(Supplier supplier,long duration,TimeUnit timenunit)
实例如下:
Supplier<Object> supp = new Supplier<Object>() {
public Object get() {
System.out.println("初始化对象。。。");
return new Object();
}
};
Supplier<Object> memoize = Suppliers.memoizeWithExpiration(supp,3, TimeUnit.SECONDS);
System.out.println(memoize.get());
System.out.println(memoize.get()); //未超时,不用重新初始化对象
TimeUnit.SECONDS.sleep(4); //这里会有异常在方法上声明了
System.out.println(memoize.get()); //超时重新初始化对象
从输出结果可以看到,超时后又重新初始化了一个新的对象
初始化对象。。。
java.lang.Object@19b49e6
java.lang.Object@19b49e6
初始化对象。。。
java.lang.Object@6ca1c