小编
专注分享Java技术,坚持原创,你的关注和转发就是我们最好的动力。
前言
在上一个章节我们讲到Java程序的函数式编程是如何发展的而来的,那么本篇我们来说下Java为函数式编程提供哪些便利的地方。
函数式接口
我们知道,方法引用和Lambda表达式使用的时候,只需要知道我们的方法签名就行,而不在乎我们的接口名字。那么java的函数式接口真是为了避免我们每次使用需要自己去创建接口而提供的。
java提供的是函数式接口位于java.util.function.*路径下面,这些接口代表了接口调用的各种不同应用场景。
Function接口
Function<T,R> 接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。
Function 接口中最主要的抽象方法为:R apply(T t) ,根据类型T的参数获取类型R的结果。下面我们将 String 类型转换为 Integer 类型:
public class Demo11FunctionApply { private static void method(Function<String, Integer> function) { int num = function.apply("10"); System.out.println(num + 20); }
public static void main(String[] args) { method(s ‐ > Integer.parseInt(s)); }}
Function 接口中有一个默认的 andThen 方法,该方法同样用于“先做什么,再做什么”的场景。下面我们来看一个例子,把传入的String字符串转成int类型,做加法操作后,把结果交给第二个Function对象:
public class Demo12FunctionAndThen { private static void method(Function<String, Integer> one, Function<Integer, Integer> two) { int num = one.andThen(two).apply("10"); System.out.println(num + 20); }
public static void main(String[] args) { method(str‐ > Integer.parseInt(str) + 10, i ‐>i *= 10); }}
Predicate接口
如果我们需要对某种数据类型进行判断,从而得到一个Boolean值结果。那么我们就可以使用到Predicate接口。
boolean test(T t)是Predicate接口中包含一个抽象方法,用在条件判断的场景中,下面我们以一个判断字符串长度为例:
private static void method(Predicate<String> predicate) { boolean veryLong = predicate.test("HelloWorld"); System.out.println("你的字符串是否超出5位字符:" + veryLong);}
public static void main(String[] args) { method(s -> s.length() > 5);}
Predicate接口有一个and和or的默认方法,用于做与和或的判断逻辑,我们以一个判断一个字符串长度既要大于5,又要小于10为例子:
private static void method(Predicate<String> one, Predicate<String> two) { boolean isValid = one.and(two).test("Helloworld"); System.out.println("字符串符合要求吗:" + isValid);}public static void main(String[] args) { method(str -> str.length()>5, str -> str.length()<6);}
“非”的逻辑关系的默认方法是negate。JDK源码中是将test方法返回值进行取反,所以一定要在test方法调用之前调用negate方法,正如and和or的方法一样。
private static void method(Predicate<String> predicate) { boolean veryLong = predicate.negate().test("HelloWorld"); System.out.println("你的字符串不是超出5位字符:" + veryLong);}
public static void main(String[] args) { method(s -> s.length() > 5);}
Supplier接口
Supplier接口用来获取一个泛型参数指定类型的对象数据,作为一个生成接口,他需要对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据:
private static String getString(Supplier<String> function) { return function.get();}public static void main(String[] args) { String msgA = "Hello"; String msgB = "World"; System.out.println(getString(() -> msgA +msgB));}
Consumer接口
Consumer<T> 接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据,void accept(T t)用于消费一个指定泛型的数据,基本使用如下
private static void consumeString(Consumer<String> function) { function.accept("Hello");}public static void main(String[] args) { consumeString(s ‐ > System.out.println(s));}
结合Stream API的时候
Stream API的reduce()使用到Function接口:
// 从1到10累计并且把计算结果打印List<Integer> values = range(1,10);Integer result = values.stream().reduce(0, Integer::sum);
Stream API的forEach()使用到Consumer接口:
// 将1-10全部打印// Consumer接口,只接收数据不返回values.stream().forEach(System.out::println);
Stream API的filter()使用到Predicate接口:
// 1到10挑选偶数,打印累计的值values.stream().filter(value -> value%2==0).reduce(0,Integer::sum);
Stream API的map()使用到Function接口:
// 1到10挑选偶数,扩大2倍values.stream().filter(value -> value%2==0).map(value -> value*2);
小结