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、源码

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

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

2、使用示例

  1. public static void main(String[] args) {
  2. testConsumer();
  3. testAndThen();
  4. }
  5. /**
  6. * 一个简单的平方计算
  7. */
  8. public static void testConsumer() {
  9. //设置好Consumer实现方法
  10. Consumer<Integer> square = x -> System.out.println("平方计算 : " + x * x);
  11. //传入值
  12. square.accept(2);
  13. }
  14. /**
  15. * 定义3个Consumer并按顺序进行调用andThen方法
  16. */
  17. public static void testAndThen() {
  18. //当前值
  19. Consumer<Integer> consumer1 = x -> System.out.println("当前值 : " + x);
  20. //相加
  21. Consumer<Integer> consumer2 = x -> { System.out.println("相加 : " + (x + x)); };
  22. //相乘
  23. Consumer<Integer> consumer3 = x -> System.out.println("相乘 : " + x * x);
  24. //andThen拼接
  25. consumer1.andThen(consumer2).andThen(consumer3).accept(1);
  26. }

运行结果

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

3、JDK8使用

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

  1. public interface Iterable<T> {
  2. //forEach方法传入的就是Consumer
  3. default void forEach(Consumer<? super T> action) {
  4. Objects.requireNonNull(action);
  5. for (T t : this) {
  6. action.accept(t);
  7. }
  8. }
  9. }

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

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

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

三、Supplier

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

1、源码

  1. @FunctionalInterface
  2. public interface Supplier<T> {
  3. /**
  4. * 只有这一个抽象类
  5. */
  6. T get();
  7. }

源码非常简单。

2、JDK8使用

在JDK8中Optional对象有使用到

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

我们看下源码

  1. public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
  2. if (value != null) {
  3. return value;
  4. } else {
  5. throw exceptionSupplier.get();
  6. }
  7. }

使用示例

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

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

四、Function

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

1、源码

  1. @FunctionalInterface
  2. public interface Function<T, R> {
  3. /**
  4. * 抽象方法: 根据一个数据类型T加工得到一个数据类型R
  5. */
  6. R apply(T t);
  7. /**
  8. * 组合函数,调用当前function之前调用
  9. */
  10. default <V> java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T> before) {
  11. Objects.requireNonNull(before);
  12. return (V v) -> apply(before.apply(v));
  13. }
  14. /**
  15. * 组合函数,调用当前function之后调用
  16. */
  17. default <V> java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V> after) {
  18. Objects.requireNonNull(after);
  19. return (T t) -> after.apply(apply(t));
  20. }
  21. /**
  22. * 静态方法,返回与原函数参数一致的结果。x=y
  23. */
  24. static <T> java.util.function.Function<T, T> identity() {
  25. return t -> t;
  26. }
  27. }

2、使用示例

  1. public static void main(String[] args) {
  2. applyTest();
  3. andThenTest();
  4. composeTest();
  5. test();
  6. }
  7. /**
  8. * 1、apply 示例
  9. */
  10. private static void applyTest() {
  11. //示例1:定义一个funciton,实现将String转换为Integer
  12. Function<String, Integer> function = x -> Integer.parseInt(x);
  13. Integer a = function.apply("100");
  14. System.out.println(a.getClass());
  15. // 结果:class java.lang.Integer
  16. }
  17. /**
  18. * 2、andThen 示例
  19. */
  20. private static void andThenTest() {
  21. //示例2:使用andThen() 实现一个函数 y=10x + 10;
  22. //先执行 10 * x
  23. Function<Integer, Integer> function2 = x -> 10 * x;
  24. //通过andThen在执行 这里的x就等于上面的10 * x的值
  25. function2 = function2.andThen(x -> x + 10);
  26. System.out.println(function2.apply(2));
  27. //结果:30
  28. }
  29. /**
  30. * 3、compose 示例
  31. */
  32. private static void composeTest() {
  33. //示例3:使用compose() 实现一个函数 y=(10+x)2;
  34. Function<Integer, Integer> function3 = x -> x * 2;
  35. //先执行 x+10 在执行(x+10)*2顺序与上面相反
  36. function3 = function3.compose(x -> x + 10);
  37. System.out.println(function3.apply(3));
  38. //结果:26
  39. }
  40. /**
  41. * 4、综合示例
  42. */
  43. private static void test() {
  44. //示例4:使用使用compose()、andThen()实现一个函数 y=(10+x)*2+10;
  45. //执行第二步
  46. Function<Integer, Integer> function4 = x -> x * 2;
  47. //执行第一步
  48. function4 = function4.compose(x -> x + 10);
  49. //执行第三步
  50. function4 = function4.andThen(x -> x + 10);
  51. System.out.println(function4.apply(3));
  52. //结果:36
  53. }

3、JDK8使用

有两个地方很常用

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

computeIfAbsent使用示例

  1. Map<String, List<String>> map = new HashMap<>();
  2. List<String> list;
  3. // java8之前写法
  4. list = map.get("key");
  5. if (list == null) {
  6. list = new LinkedList<>();
  7. map.put("key", list);
  8. }
  9. list.add("11");
  10. // 使用 computeIfAbsent 可以这样写 如果key返回部位空则返回该集合 ,为空则创建集合后返回
  11. list = map.computeIfAbsent("key", k -> new ArrayList<>());
  12. list.add("11");

stream中map使用示例

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

代码是不是又简洁了。

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

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

参考

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

2、JAVA 8 函数式接口

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

java代码之美(15)---Java8 Function、Consumer、Supplier的更多相关文章

  1. java代码之美(16) ---Java8 Optional

    Java8 Optional 一句话介绍Optional类:使用JDK8的Optional类来防止NullPointerException(空指针异常)问题. 一.前言 在我们开放过程中,碰到的异常中 ...

  2. java代码之美(17) ---Java8 LocalDateTime

    Java8 LocalDateTime 在java8之前我们在处理时间的时候都是用的Date,但它其实有很明显的缺点. 1.我们也会对日期做一些操作,比如加几天.加几分,当月的最后一天等等.有些计算实 ...

  3. java代码之美(14)---Java8 函数式接口

    Java8 函数式接口 之前写了有关JDK8的Lambda表达式:java代码之美(1)---Java8 Lambda 函数式接口可以理解就是为Lambda服务的,它们组合在一起可以让你的代码看去更加 ...

  4. java代码(14) --Java8函数式接口

    Java8函数式接口 之前有关JDK8的Lambda表达式 Java代码(1)--Java8 Lambda 函数式接口可以理解就是为Lambda服务的,它们组合在一起可以让你的代码看去更加简洁 一.概 ...

  5. java代码之美(11)---java代码的优化

    java代码的优化 随着自己做开发时间的增长,越来越理解雷布斯说的: 敲代码要像写诗一样美.也能理解有一次面试官问我你对代码有洁癖吗? 一段好的代码会让人看就像诗一样,也像一个干净房间会让人看去很舒服 ...

  6. java代码之美(3)---guava 复写Object常用方法

    guava 复写Object常用方法 Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,这个库提供用于集合,缓存,支持原语,并发性,常见注解,字符串处理,I/O和验证的实用方 ...

  7. java代码之美(10)---Java8 Map中的computeIfAbsent方法

    Map中的computeIfAbsent方法 Map接口的实现类如HashMap,ConcurrentHashMap,HashTable等继承了此方法,通过此方法可以在特定需求下,让你的代码更加简洁. ...

  8. java代码之美(2)---Java8 Stream

    Stream 第一次看到Stream表达式就深深把我吸引,用它可以使你的代码更加整洁而且对集合的操作效率也会大大提高,如果你还没有用到java8的Stream特性,那就说明你确实out啦. 一.概述 ...

  9. java代码之美(1)---Lambda

    Lambda 一.概述 1.什么是Lambda表达式 Lambda 表达式是一种匿名函数,简单地说,它是没有声明的方法,也即没有访问修饰符.返回值声明和名字. 它可以写出更简洁.更灵活的代码.作为一种 ...

随机推荐

  1. Windows安装EMQ服务器(mqtt)

    先去EMQ官网下载安装包 https://www.emqx.io/downloads#broker 注意:此处一定不能下错成企业版的,不然EMQ会由于缺少企业license无法启动服务 解压到任意路径 ...

  2. Huffman树及其编码(STL array实现)

    这篇随笔主要是Huffman编码,构建哈夫曼树有各种各样的实现方法,如优先队列,数组构成的树等,但本质都是堆. 这里我用数组来存储数据,以堆的思想来构建一个哈弗曼树,并存入vector中,进而实现哈夫 ...

  3. Go 每日一库之 flag

    缘起 我一直在想,有什么方式可以让人比较轻易地保持每日学习,持续输出的状态.写博客是一种方式,但不是每天都有想写的,值得写的东西. 有时候一个技术比较复杂,写博客的时候经常会写着写着发现自己的理解有偏 ...

  4. js中排序方法sort() 和 reverse()

    reverse() 作用:反转原数组. 用法: array.reverse(); 图解: sort() 作用:对原数组进行排序.默认将每个数组项 先 转换为字符串 再 进行字符串对比后升序排序. 用法 ...

  5. 双重 hash

    #include<stdio.h> #include<map> #include<queue> #include<algorithm> using na ...

  6. Java同步与异步

    一.关键字: thread(线程).thread-safe(线程安全).intercurrent(并发的) synchronized(同步的).asynchronized(异步的). volatile ...

  7. html转成pdf 下载,支持后台保存

    最近有个需求,需要将html转换成pdf并支持下载 1.需要两个js库 下载 提取码: vab7 <script type="text/javascript" src=&qu ...

  8. scrapy持久化到Excel表格

    前提条件: 防止乱码产生 ITEM_PIPELINES = { 'xpc.pipelines.ExcelPipeline': 300, } 方法一 1.安装openpyxl conda install ...

  9. 11.黑窗口、IDEA生成JavaDoc

    JavaDoc: 它是一种技术,可以将一些注释信息生成一个帮助文档,就类似于Java的API JavaAPI帮助文档: https://www.oracle.com/cn/java/technolog ...

  10. 异数OS 织梦师-水桶(三)-- RAM共享存储方案

    . 异数OS 织梦师-水桶(三)– RAM共享存储方案 本文来自异数OS社区 github: https://github.com/yds086/HereticOS 异数OS社区QQ群: 652455 ...