Java通过Guava库来简单实现函数式的编码风格

下午coding的时候遇到了这么一个问题,有一个建索引的服务,需要用一个临时文件来存储一份待修改索引数据的ID列表,想设计一个通用的接口来从临时文件中读取ID,并返回java.util.List类型的结果,但是有一个问题就是ID从文件中读出的时候都是字符串类型,而Java对象中对应的ID类型并不是只有字符串类型,可能会有其它类型,像是int或者long,返回List 的时候对应的元素类型也将希望是Java中对象的对应类型。这个过程蛋疼的地方在于类型的转换,Java中最简单的做法可能如下:

        public <T> List<T> readUpdatedIdList(String file, Class<T> type);

        这种形式的接口会根据传入的type参数来执行相应的类型转换。这种写法最大的不好处就是需要在具体的实现中去依靠if else来判断,每引入一种新的类型,就会加一个判断。这还算好,如果不同的业务文件格式不同,即时类型一样,可能转换的逻辑也不一样,那这种写法就无能为力了。

        不过对于函数式语言来说,解决这种问题是非常简单的,只需要把处理的逻辑写成一个函数,把这个函数以参数的方式传递给readUpdatedIdList方法供迭代时回调就可以了。可惜的是Java7以及之前的版本是没有独立的函数这一概念的,要模拟回调,只能把参数和返回值抽象出来作为一个接口,然后构建匿名类实现此接口的方式来实现回调。比如:

 public interface TransformLogic<ReturnValue, ArgValue> {

      public ReturnValue handle(ArgValue arg);

 }

 public <ReturnValue, ArgValue> List<ReturnValue>  readUpdatedIdList(String file, TransformLogic<ReturnValue, ArgValue>  transformLogic);

        然后调用的时候就是这样:

readUpdatedIdList(recordFile, new TransformLogic <Integer, String>(){

                    public Integer handle(String line){

                            return NumberUtils.toInt(line, 0);
                    }

 });

        但是后来发现自己没必要去写一个TransformLogic接口,因为Google Guava库早就实现了一个叫做Function的接口来做这种事情,并且Guava中的Function跟Guava中的其它工具很好的融合在了一起,能够很简单方便的完成我们日常的许多工作,尤其是在遍历集合操作方面。

(注:Google Guava库是Google的一个开源Java项目,应该是原先Google内部所使用的一个类库,后来整理开源出来供大家使用,这个库涵盖我们日常Java开发的方方面面,包括集合操作、字符串处理、并发、I/O等。这套库的设计引入了很多新的理念,研究一下可能会使你对Java这门语言有新的认识和看法,项目地址:http://code.google.com/p/guava-libraries/)

下面来看一下Guava是如何在Java语言中模拟函数式的。Guava提供了两种最为基本的函数式接口形式。首先是前面所说的Function<F, T>,这个接口有两个泛型参数,F代表的是函数输入的参数类型,T代表的是函数处理的返回类型。有两个方法需要覆盖,一个是T apply(F input); 这里面需要定义函数处理的逻辑;另一个是boolean equals(Object);这个方法用于两个函数式的比较,Function主要用于根据参数来计算返回结果的地方。第二种形式是Predicate<T>,它也是有一个名为apply的方法和一个equals方法,但是与Function的apply不同的是它接受一个参数返回一个boolean值,boolean apply(T t); Predicate主要是用于筛选,计算一个值是不是符合条件,比较适合用在过滤器之类的场所。Guava在操作集合的工具类中多处使用了这两个回调接口来进行处理。

1.在迭代器中进行过滤, 筛选出所有的偶数:

Range<Integer> range = Ranges.closed(1, 12);
Iterable<Integer> iterable = Iterables.filter(range.asSet(DiscreteDomains.integers()), new Predicate<Integer>() {

            @Override
            public boolean apply(Integer input) {
                return input % 2 == 0;
            }

           });

2.对迭代器中的元素进行改变,每个元素增加一倍:

Range<Integer> range = Ranges.closed(1, 12);

Iterable<Integer> iterable = Iterables.transform(range.asSet(DiscreteDomains.integers()),
                new Function<Integer, Integer>() {

                    @Override
                    public Integer apply(Integer input) {

                        return input * 2;
                    }

                });

这两个操作是我们进行集合元素迭代经常会用到的,Guava帮助我们很好的抽象了出来。另外在Java8中会引入Lambda表达式,到时候可能就不需要使用Guava的函数式模拟功能了,那时Java会在语言特性中直接支持函数式功能,在这之前,我们可以考虑使用Guava。

你可能感兴趣的:(java,guava,函数式)