IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> java8系列05——方法引用与流的高级用法 -> 正文阅读

[Java知识库]java8系列05——方法引用与流的高级用法

1.方法引用

方法引用也是一个语法糖,可以进一步简化Lambda表达式。并不是所有的Lambda表达式和匿名内部类都可以转换为方法引用。

1.1 使用场景

在一个匿名内部类中,如果方法体中仅仅是一个方法的调用,或者是一个构造方法,那么它很可能就可以改造成为方法引用。

例:

 private static void test38() {
        getAuthors().stream()
                .map(author -> author.getName())
                .forEach(authorName -> System.out.println(authorName));
    }

对应的方法引用。

  private static void test38() {
        getAuthors().stream()
                .map(Author::getName)
                .forEach(System.out::println);
    }
1.2 语法详解(了解)

(1)引用类的静态方法

基本格式 类名::方法名

在一个匿名内部类中,如果方法体重写的方法中仅仅是一个某个类的静态方法的调用,并且,将要重写的抽象方法中所有参数都按照顺序传入到这个方法中。比如上例中的println方法。

(2)引用对象的实例方法

基本格式 对象名::方法名

在一个匿名内部类中,如果方法体重写的方法中仅仅是一个某个对象的成员方法的调用,并且,将要重写的抽象方法中所有参数都按照顺序传入到这个方法中。

例:

private static void test39() {
        StringBuilder sb = new StringBuilder();
        getAuthors().stream()
                .map(Author::getName)
                .forEach(new Consumer<String>() {
                    @Override
                    public void accept(String s) {
                        sb.append(s);
                    }
                });
        System.out.println(sb);
    }

其对应的方法引用。

  private static void test39() {
        StringBuilder sb = new StringBuilder();
        getAuthors().stream()
                .map(Author::getName)
                .forEach(sb::append);
        System.out.println(sb);
    }

(3)引用类的实例方法。

基本格式 类名::方法名

如果我们在重写方法时,方法体中只有一行代码,并且这行代码调用了第一个参数的成员方法,并且我们把抽象方法中剩余的参数按照顺序传入这个成员方法中,这个时候就可以使用类的实例方法。

例:

public class MethodDemo {
     interface UseString {
        String use(String str, int start, int length);
    }

    public static String subAuthorName(String str, UseString us) {
         int start = 0;
         int length = 1;
         return us.use(str, start, length);
    }

    public static void main(String[] args) {
        subAuthorName("半旧518", new UseString() {
            @Override
            public String use(String str, int start, int length) {
                return str.substring(start, length);
            }
        });
    }
}

其方法引用为。

public class MethodDemo {
     interface UseString {
        String use(String str, int start, int length);
    }

    public static String subAuthorName(String str, UseString us) {
         int start = 0;
         int length = 1;
         return us.use(str, start, length);
    }

    public static void main(String[] args) {
        String subName = subAuthorName("半旧518", String::substring);
        System.out.println(subName);
    }
}

实际上,我们最开始的Author::getName就是第三中方法引用。

当然,记不住还是可以在Idea中用alt键和enter键来快速的实现转换。

(4)构造器引用

如果匿名内部类在重写方法时,方法体中只有一行代码,并且这行代码就是调用某个构造方法,就可以使用构造器引用。

例:

  private static void test40() {
        getAuthors().stream()
                .map(author -> author.getName())
                .map(name -> new StringBuilder(name))
                .map(sb -> sb.append("---"))
                .forEach(System.out::println);
    }

方法引用对应如下。

  private static void test40() {
        getAuthors().stream()
                .map(Author::getName)
                .map(StringBuilder::new)
                .map(sb -> sb.append("---"))
                .forEach(System.out::println);
    }

2.Stream流的高级用法

2.1 基本数据类型的优化

参考如下代码。

 private static void test41() {
        getAuthors().stream()
                .map(author -> author.getAge() + 10)
                .filter(age -> age > 28)
                .forEach(System.out::println);
    }

看上去好像没有什么问题。转换为匿名内部类看看。

 private static void test41() {
        getAuthors().stream()
                .map(new Function<Author, Integer>() {
                    @Override
                    public Integer apply(Author author) {
                        return author.getAge() + 10;
                    }
                })
                .filter(new Predicate<Integer>() {
                    @Override
                    public boolean test(Integer age) {
                        return age > 18;
                    }
                })
                .forEach(System.out::println);
    }

applytest中参数类型都包含基本数据类型Integer,在进行运算时,会先自动拆箱,再自动装箱,如果操作的数据元素特别多,这会造成不小的时间损耗.

java8对于基本数据类型的操作提供优化的方法:mapToInt,mapToLong…可以把流中的数据类型转换为基本数据类型,对上面的例子优化如下.

   private static void test41() {
        getAuthors().stream()
                .mapToInt(Author::getAge)
                .map(age -> age + 10)
                .filter(age -> age > 18)
                .forEach(System.out::println);
    }
2.2 并行流

我们之前操作的流都是以串行的方式完成,对于大数据量的情况,串行的方式时间损耗会较大.java8提供了并行流,将数据的处理分配到多个线程进行处理.而且这种方式比自己实现多线程更加的轻量级,也不要考虑头疼的线程安全问题。使用parallel即可实现并行流。

例:

    private static void test42() {
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
        Integer intNum = integerStream.filter(num -> num > 5)
                .reduce(new BinaryOperator<Integer>() {
                    @Override
                    public Integer apply(Integer result, Integer num) {
                        return result + num;
                    }
                }).get();
        System.out.println(intNum);
    }

并行流的方式如下。

 private static void test42() {
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Integer intNum = integerStream
                .parallel()
                .filter(num -> num > 5)
                .reduce(new BinaryOperator<Integer>() {
                    @Override
                    public Integer apply(Integer result, Integer num) {
                        return result + num;
                    }
                }).get();
        System.out.println(intNum);
    }

并行流的机制其实类似与流水线,比如前5个元素在线程1中完成过滤,后5个线程会在第2个线程中完成过滤.

3.3 调试

我们可以使用peek方法帮助我们进行调试,它不会像终结方法一样将流废弃。

    private static void test42() {
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
        Integer intNum = integerStream
                .parallel()
                .peek(integer -> System.out.println(integer + " in " + Thread.currentThread()))
                .filter(num -> num > 5)
                .reduce((result, num) -> result + num).get();
        System.out.println(intNum);
    }

输出如下。

9 in Thread[ForkJoinPool.commonPool-worker-13,5,main]
4 in Thread[ForkJoinPool.commonPool-worker-15,5,main]
2 in Thread[ForkJoinPool.commonPool-worker-11,5,main]
8 in Thread[ForkJoinPool.commonPool-worker-2,5,main]
7 in Thread[ForkJoinPool.commonPool-worker-4,5,main]
6 in Thread[main,5,main]
1 in Thread[ForkJoinPool.commonPool-worker-6,5,main]
3 in Thread[ForkJoinPool.commonPool-worker-9,5,main]
5 in Thread[ForkJoinPool.commonPool-worker-8,5,main]
30
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-08 22:14:58  更:2022-03-08 22:15:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:30:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码