java代码之美(15)---Java8 Function、Consumer、Supplier java代码之美(15)---Java8 Function、Consumer、Supplier

摘自:https://www.cnblogs.com/qdhxhz/p/12050701.html

java代码之美(15)---Java8 Function、Consumer、Supplier

Java8 Function、Consumer、Supplier

有关JDK8新特性之前写了三篇博客:

1、java代码之美(1)---Java8 Lambda

2、java代码之美(2)---Java8 Stream

3、java代码之美(13)--- Predicate详解

这一篇我们来了解JDK8已经定义好的几个函数式接口。

一、概述

Jdk8之后新增的一个重要的包 : java.util.function

该包下所有的接口都是函数式接口, 按分类主要分为四大接口类型: FunctionConsumerPredicateSupplier。有关Predicate这里不再讲解,因为上面有单独写过一篇博客。

延伸如下

这里也仅仅是展示一部分,我们看看java.util.function包下

二、Consumer

作用 一听这名字就知道是消费某个对象,没有返回值。

1、源码

在源码中只有两个方法,一个抽象方法,一个默认方法。

@FunctionalInterface
public interface Consumer<T> { /** * 抽象方法:传入一个指定泛型的参数,无返回值 */ void accept(T t); /** * 如同方法名字一样andThen,类似一种相加的功能(下面会举例说明) */ default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }

2、使用示例

    public static void main(String[] args) { testConsumer(); testAndThen(); } /** * 一个简单的平方计算 */ public static void testConsumer() { //设置好Consumer实现方法 Consumer<Integer> square = x -> System.out.println("平方计算 : " + x * x); //传入值 square.accept(2); } /** * 定义3个Consumer并按顺序进行调用andThen方法 */ public static void testAndThen() { //当前值 Consumer<Integer> consumer1 = x -> System.out.println("当前值 : " + x); //相加 Consumer<Integer> consumer2 = x -> { System.out.println("相加 : " + (x + x)); }; //相乘 Consumer<Integer> consumer3 = x -> System.out.println("相乘 : " + x * x); //andThen拼接 consumer1.andThen(consumer2).andThen(consumer3).accept(1); }

运行结果

单个这样消费看去并没啥意义,但如果是集合操作就有意义了,所以Jdk8的Iterator接口就引入了Consumer。

3、JDK8使用

Iterable接口的forEach方法需要传入Consumer,大部分集合类都实现了该接口,用于返回Iterator对象进行迭代。

public interface Iterable<T> { //forEach方法传入的就是Consumer default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } } }

我们在看给我们带来的便利

    public static void main(String[] args) { //假设这里有个集合,集合里的对象有个status属性,现在我想对这个属性赋值一个固定值 List<Pension> pensionList = new ArrayList<>(); //1、传统的通过for循环添加 for (Pension pension : pensionList) { pension.setStatus(1); } //2、通过forEach的Consumer添加 pensionList.forEach(x -> x.setStatus(1)); }

这样一比较是不是代码简洁了点,这就是Consumer是我们代码带来简洁的地方。

三、Supplier

作用 提前定义可能返回的一个指定类型结果,等需要调用的时候再获取结果。

1、源码

@FunctionalInterface
public interface Supplier<T> { /** * 只有这一个抽象类 */ T get(); }

源码非常简单。

2、JDK8使用

在JDK8中Optional对象有使用到

Optional.orElseGet(Supplier<? extends T>) //当this对象为null,就通过传入supplier创建一个T返回。

我们看下源码

 public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { if (value != null) { return value; } else { throw exceptionSupplier.get(); } }

使用示例

  public static void main(String[] args) { Person son = null; //先判断son是否为null,如果为不为null则返回当前对象,如果为null则返回新创建的对象 BrandDTO optional = Optional.ofNullable(son).orElseGet(() -> new Person()); }

这样代码是不是又简单了。有关Optional这里就不多说,接下来会单独写一篇博客。

四、Function

作用 实现一个”一元函数“,即传入一个值经过函数的计算返回另一个值。

1、源码

    @FunctionalInterface
    public interface Function<T, R> { /** * 抽象方法: 根据一个数据类型T加工得到一个数据类型R */ R apply(T t); /** * 组合函数,调用当前function之前调用 */ default <V> java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } /** * 组合函数,调用当前function之后调用 */ default <V> java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } /** * 静态方法,返回与原函数参数一致的结果。x=y */ static <T> java.util.function.Function<T, T> identity() { return t -> t; } }

2、使用示例

public static void main(String[] args) { applyTest(); andThenTest(); composeTest(); test(); } /** * 1、apply 示例 */ private static void applyTest() { //示例1:定义一个funciton,实现将String转换为Integer Function<String, Integer> function = x -> Integer.parseInt(x); Integer a = function.apply("100"); System.out.println(a.getClass()); // 结果:class java.lang.Integer } /** * 2、andThen 示例 */ private static void andThenTest() { //示例2:使用andThen() 实现一个函数 y=10x + 10; //先执行 10 * x Function<Integer, Integer> function2 = x -> 10 * x; //通过andThen在执行 这里的x就等于上面的10 * x的值 function2 = function2.andThen(x -> x + 10); System.out.println(function2.apply(2)); //结果:30 } /** * 3、compose 示例 */ private static void composeTest() { //示例3:使用compose() 实现一个函数 y=(10+x)2; Function<Integer, Integer> function3 = x -> x * 2; //先执行 x+10 在执行(x+10)*2顺序与上面相反 function3 = function3.compose(x -> x + 10); System.out.println(function3.apply(3)); //结果:26 } /** * 4、综合示例 */ private static void test() { //示例4:使用使用compose()、andThen()实现一个函数 y=(10+x)*2+10; //执行第二步 Function<Integer, Integer> function4 = x -> x * 2; //执行第一步 function4 = function4.compose(x -> x + 10); //执行第三步 function4 = function4.andThen(x -> x + 10); System.out.println(function4.apply(3)); //结果:36 }

3、JDK8使用

有两个地方很常用

1、V HashMap.computeIfAbsent(K , Function<K, V>) // 简化代码,如果指定的键尚未与值关联或与null关联,使用函数返回值替换。
2、<R> Stream<R> map(Function<? super T, ? extends R> mapper); // 转换流

computeIfAbsent使用示例

Map<String, List<String>> map = new HashMap<>();
List<String> list;

// java8之前写法
list = map.get("key");
if (list == null) { list = new LinkedList<>(); map.put("key", list); } list.add("11"); // 使用 computeIfAbsent 可以这样写 如果key返回部位空则返回该集合 ,为空则创建集合后返回 list = map.computeIfAbsent("key", k -> new ArrayList<>()); list.add("11");

stream中map使用示例

  public static void main(String[] args) { List<Person> persionList = new ArrayList<Person>(); persionList.add(new Person(1,"张三","男",38)); persionList.add(new Person(2,"小小","女",2)); persionList.add(new Person(3,"李四","男",65)); //1、只取出该集合中所有姓名组成一个新集合(将Person对象转为String对象) List<String> nameList=persionList.stream().map(Person::getName).collect(Collectors.toList()); System.out.println(nameList.toString()); }

代码是不是又简洁了。

总结 这些函数式接口作用在我看来,就是定义一个方法,方法中有个参数是函数式接口,这样的话函数的具体实现则由调用者来实现。这就是函数式接口的意义所在。

一般我们也会很少去定义一个方法,方法参数包含函数接口。我们更重要的是学会使用JDk8中带有函数式接口参数的方法,来简化我们的代码。

参考

1、JDK1.8函数式接口Function、Consumer、Predicate、Supplier

2、JAVA 8 函数式接口




你如果愿意有所作为,就必须有始有终。(25)
 
Java8 Function、Consumer、Supplier

有关JDK8新特性之前写了三篇博客:

1、java代码之美(1)---Java8 Lambda

2、java代码之美(2)---Java8 Stream

3、java代码之美(13)--- Predicate详解

这一篇我们来了解JDK8已经定义好的几个函数式接口。

一、概述

Jdk8之后新增的一个重要的包 : java.util.function

该包下所有的接口都是函数式接口, 按分类主要分为四大接口类型: FunctionConsumerPredicateSupplier。有关Predicate这里不再讲解,因为上面有单独写过一篇博客。

延伸如下

这里也仅仅是展示一部分,我们看看java.util.function包下

二、Consumer

作用 一听这名字就知道是消费某个对象,没有返回值。

1、源码

在源码中只有两个方法,一个抽象方法,一个默认方法。

@FunctionalInterface
public interface Consumer<T> { /** * 抽象方法:传入一个指定泛型的参数,无返回值 */ void accept(T t); /** * 如同方法名字一样andThen,类似一种相加的功能(下面会举例说明) */ default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }

2、使用示例

    public static void main(String[] args) { testConsumer(); testAndThen(); } /** * 一个简单的平方计算 */ public static void testConsumer() { //设置好Consumer实现方法 Consumer<Integer> square = x -> System.out.println("平方计算 : " + x * x); //传入值 square.accept(2); } /** * 定义3个Consumer并按顺序进行调用andThen方法 */ public static void testAndThen() { //当前值 Consumer<Integer> consumer1 = x -> System.out.println("当前值 : " + x); //相加 Consumer<Integer> consumer2 = x -> { System.out.println("相加 : " + (x + x)); }; //相乘 Consumer<Integer> consumer3 = x -> System.out.println("相乘 : " + x * x); //andThen拼接 consumer1.andThen(consumer2).andThen(consumer3).accept(1); }

运行结果

单个这样消费看去并没啥意义,但如果是集合操作就有意义了,所以Jdk8的Iterator接口就引入了Consumer。

3、JDK8使用

Iterable接口的forEach方法需要传入Consumer,大部分集合类都实现了该接口,用于返回Iterator对象进行迭代。

public interface Iterable<T> { //forEach方法传入的就是Consumer default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } } }

我们在看给我们带来的便利

    public static void main(String[] args) { //假设这里有个集合,集合里的对象有个status属性,现在我想对这个属性赋值一个固定值 List<Pension> pensionList = new ArrayList<>(); //1、传统的通过for循环添加 for (Pension pension : pensionList) { pension.setStatus(1); } //2、通过forEach的Consumer添加 pensionList.forEach(x -> x.setStatus(1)); }

这样一比较是不是代码简洁了点,这就是Consumer是我们代码带来简洁的地方。

三、Supplier

作用 提前定义可能返回的一个指定类型结果,等需要调用的时候再获取结果。

1、源码

@FunctionalInterface
public interface Supplier<T> { /** * 只有这一个抽象类 */ T get(); }

源码非常简单。

2、JDK8使用

在JDK8中Optional对象有使用到

Optional.orElseGet(Supplier<? extends T>) //当this对象为null,就通过传入supplier创建一个T返回。

我们看下源码

 public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { if (value != null) { return value; } else { throw exceptionSupplier.get(); } }

使用示例

  public static void main(String[] args) { Person son = null; //先判断son是否为null,如果为不为null则返回当前对象,如果为null则返回新创建的对象 BrandDTO optional = Optional.ofNullable(son).orElseGet(() -> new Person()); }

这样代码是不是又简单了。有关Optional这里就不多说,接下来会单独写一篇博客。

四、Function

作用 实现一个”一元函数“,即传入一个值经过函数的计算返回另一个值。

1、源码

    @FunctionalInterface
    public interface Function<T, R> { /** * 抽象方法: 根据一个数据类型T加工得到一个数据类型R */ R apply(T t); /** * 组合函数,调用当前function之前调用 */ default <V> java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } /** * 组合函数,调用当前function之后调用 */ default <V> java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } /** * 静态方法,返回与原函数参数一致的结果。x=y */ static <T> java.util.function.Function<T, T> identity() { return t -> t; } }

2、使用示例

public static void main(String[] args) { applyTest(); andThenTest(); composeTest(); test(); } /** * 1、apply 示例 */ private static void applyTest() { //示例1:定义一个funciton,实现将String转换为Integer Function<String, Integer> function = x -> Integer.parseInt(x); Integer a = function.apply("100"); System.out.println(a.getClass()); // 结果:class java.lang.Integer } /** * 2、andThen 示例 */ private static void andThenTest() { //示例2:使用andThen() 实现一个函数 y=10x + 10; //先执行 10 * x Function<Integer, Integer> function2 = x -> 10 * x; //通过andThen在执行 这里的x就等于上面的10 * x的值 function2 = function2.andThen(x -> x + 10); System.out.println(function2.apply(2)); //结果:30 } /** * 3、compose 示例 */ private static void composeTest() { //示例3:使用compose() 实现一个函数 y=(10+x)2; Function<Integer, Integer> function3 = x -> x * 2; //先执行 x+10 在执行(x+10)*2顺序与上面相反 function3 = function3.compose(x -> x + 10); System.out.println(function3.apply(3)); //结果:26 } /** * 4、综合示例 */ private static void test() { //示例4:使用使用compose()、andThen()实现一个函数 y=(10+x)*2+10; //执行第二步 Function<Integer, Integer> function4 = x -> x * 2; //执行第一步 function4 = function4.compose(x -> x + 10); //执行第三步 function4 = function4.andThen(x -> x + 10); System.out.println(function4.apply(3)); //结果:36 }

3、JDK8使用

有两个地方很常用

1、V HashMap.computeIfAbsent(K , Function<K, V>) // 简化代码,如果指定的键尚未与值关联或与null关联,使用函数返回值替换。
2、<R> Stream<R> map(Function<? super T, ? extends R> mapper); // 转换流

computeIfAbsent使用示例

Map<String, List<String>> map = new HashMap<>();
List<String> list;

// java8之前写法
list = map.get("key");
if (list == null) { list = new LinkedList<>(); map.put("key", list); } list.add("11"); // 使用 computeIfAbsent 可以这样写 如果key返回部位空则返回该集合 ,为空则创建集合后返回 list = map.computeIfAbsent("key", k -> new ArrayList<>()); list.add("11");

stream中map使用示例

  public static void main(String[] args) { List<Person> persionList = new ArrayList<Person>(); persionList.add(new Person(1,"张三","男",38)); persionList.add(new Person(2,"小小","女",2)); persionList.add(new Person(3,"李四","男",65)); //1、只取出该集合中所有姓名组成一个新集合(将Person对象转为String对象) List<String> nameList=persionList.stream().map(Person::getName).collect(Collectors.toList()); System.out.println(nameList.toString()); }

代码是不是又简洁了。

总结 这些函数式接口作用在我看来,就是定义一个方法,方法中有个参数是函数式接口,这样的话函数的具体实现则由调用者来实现。这就是函数式接口的意义所在。

一般我们也会很少去定义一个方法,方法参数包含函数接口。我们更重要的是学会使用JDk8中带有函数式接口参数的方法,来简化我们的代码。

参考

1、JDK1.8函数式接口Function、Consumer、Predicate、Supplier

2、JAVA 8 函数式接口




你如果愿意有所作为,就必须有始有终。(25)

猜你喜欢

转载自www.cnblogs.com/xichji/p/12332217.html