通过java8 stream-api的map方法理解函数式编程思想。
例如:现在有一个字符串数组
String[] strings = new String[]{"1", "2", "3"};
现在要把数组中的字符串转为Integer类型,返回一个Integer的数组。
使用stream-api的map方法实现就是:
Integer[] res = Arrays.stream(strings).map(Integer::parseInt)
.toArray(Integer[]::new);
这个map的完整形式是这样的:
class Anonymous implements Function<String, Integer> {
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
}
Anonymous anonymous = new Anonymous();
Integer[] res = Arrays.stream(strings).map(anonymous)
.toArray(Integer[]::new);
map接收一个Function类型的对象,并在内部调用该接口的apply方法
所以我们需要实现其提供的Function接口的apply方法。并把实例传给map方法。
在面向对象编程环境中,方法的参数一定是一个对象。在这个思想的影响下,我们会潜意识的认为一个对象最重要的就是对象内的状态数据(成员变量),一般实际应用中,将对象作为参数传给一个方法,目的是操作他的内部数据。
而在面向函数编程中,参数不一定是对象,也可以是一个无状态的函数。
上面的代码使用匿名内部类简化后就是:
Integer[] res = Arrays.stream(strings).map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
}).toArray(Integer[]::new);
如果再使用lambda表达式简化后就是:
Integer[] res = Arrays.stream(strings).map((s) -> {
return Integer.parseInt(s);
}).toArray(Integer[]::new);
再次简化就是:(如果方法实现只有一行,返回值相同,省略return和{})
Integer[] res = Arrays.stream(strings).map(s -> Integer.parseInt(s))
.toArray(Integer[]::new);
最后在简化:(如果parseInt参数和Function参数相同,省略参数)
Integer[] res = Arrays.stream(strings).map(Integer::parseInt)
.toArray(Integer[]::new);
代码逻辑非常清晰,书写非常舒服。例如:
Integer sum = Stream.of(strings1, strings1)
.flatMap(Arrays::stream)
.filter(Objects::nonNull)
.filter(s -> !s.trim().equals(""))
.map(Integer::parseInt)
.sorted(Integer::compareTo)
.limit(5)
.peek(this::log)
.reduce(0, Integer::sum);