前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java8系列05——方法引用与流的高级用法

java8系列05——方法引用与流的高级用法

作者头像
用户10127530
发布2022-10-26 17:41:02
2280
发布2022-10-26 17:41:02
举报
文章被收录于专栏:半旧的技术栈

目录

1.方法引用

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

1.1 使用场景

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

例:

代码语言:javascript
复制
 private static void test38() {
        getAuthors().stream()
                .map(author -> author.getName())
                .forEach(authorName -> System.out.println(authorName));
    }

对应的方法引用。

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

(1)引用类的静态方法

基本格式 类名::方法名

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

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

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

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

例:

代码语言:javascript
复制
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);
    }

其对应的方法引用。

代码语言:javascript
复制
  private static void test39() {
        StringBuilder sb = new StringBuilder();
        getAuthors().stream()
                .map(Author::getName)
                .forEach(sb::append);
        System.out.println(sb);
    }

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

基本格式 类名::方法名

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

例:

代码语言:javascript
复制
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);
            }
        });
    }
}

其方法引用为。

代码语言:javascript
复制
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)构造器引用

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

例:

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

方法引用对应如下。

代码语言:javascript
复制
  private static void test40() {
        getAuthors().stream()
                .map(Author::getName)
                .map(StringBuilder::new)
                .map(sb -> sb.append("---"))
                .forEach(System.out::println);
    }

2.Stream流的高级用法

2.1 基本数据类型的优化

参考如下代码。

代码语言:javascript
复制
 private static void test41() {
        getAuthors().stream()
                .map(author -> author.getAge() + 10)
                .filter(age -> age > 28)
                .forEach(System.out::println);
    }

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

代码语言:javascript
复制
 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…可以把流中的数据类型转换为基本数据类型,对上面的例子优化如下.

代码语言:javascript
复制
   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即可实现并行流。

例:

代码语言:javascript
复制
    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);
    }

并行流的方式如下。

代码语言:javascript
复制
 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方法帮助我们进行调试,它不会像终结方法一样将流废弃。

代码语言:javascript
复制
    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);
    }

输出如下。

代码语言:javascript
复制
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
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-03-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
  • 1.方法引用
    • 1.1 使用场景
      • 1.2 语法详解(了解)
      • 2.Stream流的高级用法
        • 2.1 基本数据类型的优化
          • 2.2 并行流
            • 3.3 调试
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档