目录
- 简介
- 函数式编程
- 例1:T reduce(T identity, BinaryOperator accumulator)
- 例2: collect(Collector collector)
- 另:
简介
最近看到别人写的项目中有看不太懂的东西,于是就单独学习了一哈,拿出来记录一下。
本文以java.util.stream类的reduce(T identity, BinaryOperator accumulator)方法和collect(Collector collector)方法为例子讲述函数式编程是个啥,有啥用。
函数式编程
函数式接口的定义:指(只拥有一个未实现的方法的)接口
例子:
Consumer c = o -> System.out.println(o);
c.apply("hello,world~")
这个例子中,等号左边的Consumer是一个函数式接口,内含一个未实现的void apply(T t)方法(见源码),而等号右边的函数则是对这个apply方法的实现。
当然,比较常见的用处并不是用等号直接将实现函数赋值给函数式接口,而是将实现函数以参数传递给所需要这个接口的方法中去,见例1。
直观上可看出来的好处:一个函数式接口的实质也就是个函数,函数式接口可以配合lambda表达式作为参数传递到各个方法内,即一些代码段可以作为参数传递到函数内部去,直观的可以感觉出来这样是挺简洁的,感觉可以共用一些代码段,然后自己再自定义一些代码段,从而少写点代码~
例1:T reduce(T identity, BinaryOperator accumulator)
stream流是一个用于处理集合的类,内置了很多有用的方法如reduce、collect来对流中的数据进行处理,其中reduce()接口重载了3种方法,其中含有2个参数的方法reduce(T identity, BinaryOperator accumulator)的内部实现主要为:
T result = identity;
for(T item : this stream)
result = accumulator.apply(result,item)
return result;
由以上源码可看出,reduce实质上就是一个对传入集合流的迭代操作器~
传入的函数式接口即函数也就是继承了BiConsumer接口的BinaryOperator接口的apply方法,其定义如下:
T apply(T result, T item);
/**
注:
* 原BiConsumer接口中的apply的定义为:R apply(T t, U u) ~~~
* 第一个参数对应reduce中的result,第二个参数对应reduce中的item
* item项即为list.stream().reduce(.....)中的list中的每一项
*/
reduce的参数BinaryOperator accumulator作为一个函数式接口,需要传入个重写了apply(result,item)的函数实现之,当然也可以使用lambda表达式。
其中,BinaryOperator 接口继承了BiConsumer<T,T,T>接口【自然继承了其apply(T,T)方法,见源码】,这个BinaryOperator的作用也就是将BiConsumer<T,U,R>变为了BiConsumer<T,T,T>并再添加了2个新方法~(见源码)
例:需要计算1-3的和
//用Arrays.asList(1,2,3)来快速生成一个List,用list.stream()将这个list转为stream() [注:这一步并不是直接引用原list的地址]
int sum = Arrays.asList(1,2,3).stream().reduce(0,(result,item)->(result+item))
System.out.println("sum(1-3) = "+sum)
例2: collect(Collector collector)
源码看不太懂,举个例子来表达它的作用吧:
例子:已有Set<Map.Entry<Integer, String>> s,可将其转化为一个Map<String, String>,过程如下:
Map<Integer,String> map = new HashMap<>();
map.put(1,"N1");
map.put(2,"N2");
Set<Map.Entry<Integer, String>> s = map.entrySet();
Map<String,String> m2 = s.stream().collect(Collectors.toMap(e -> String.valueOf(e.getKey()), Map.Entry::getValue));
System.out.println("after convert,m = "+m2);
其中Collectors.toMap方法中的Function中的apply(T ele)中的ele指的是传入的Set s的每一个T类型的元素
另:
- 双冒号简写lambda函数~ 如:person->person.getName() 等价于 Person::getName()
- Java提供了3个函数式接口:Consumer、Function、Predicate,而在Java中Stream类、Optional类都封装了许多方法,这些方法都用到了函数式接口。