`
gaozzsoft
  • 浏览: 413235 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类

JAVA 8的Lambda表达式和Stream API研究

 
阅读更多

JAVA 8 Lambda表达式简化了代码开发,代码简洁,类似Python。

代码实现例子:

 

new Thread(() -> System.out.println("It's a lambda function!")).start();

 

List<String> languagesList = Arrays.asList("java","scala","python");

languagesList.forEach(x -> System.out.println(x));

languagesList.forEach(System.out::println);

 

 

List<Double> costList = Arrays.asList(10.0, 20.0,30.0);

costList.stream().map(x -> x + x*0.05).forEach(x -> System.out.println(x));

 

 

 

List<Double> costList = Arrays.asList(10.0, 20.0,30.0);

double allCost = costList.stream().map(x -> x+x*0.05).reduce((sum,x) -> sum + x).get();

System.out.println(allCost);

 

 

 

List<Double> costList = Arrays.asList(10.0, 20.0,30.0,40.0);

List<Double> filteredCostList = costList.stream().filter(x -> x > 25.0).collect(Collectors.toList());

filteredCostList.forEach(x -> System.out.println(x));

 

 

 

List<String> languagesList = Arrays.asList("Java","Python","scala","Shell","R");

filterTest(languagesList,x -> x.startsWith("J"));

 

public static void filterTest(List<String> languagesList, Predicate<String> condition) {

  languagesList.stream().filter(x -> condition.test(x)).forEach(x -> System.out.println(x + " "));

}

 

============================================================================

 

通过使用Stream API对集合数据进行操作,就类似于使用 SQL 执行的数据库查询,也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

 

 

List<Integer> list = Arrays.asList(2, 3, 5, 4, 1, 8, 10, 9, 7, 6);

list.stream().filter((e) -> e > 5).forEach(System.out::println);

 

 

使用Stream操作有三个步骤

 

创建 Stream:从一个数据源(如集合、数组)中获取一个流

中间操作:一个或多个中间操作,对数据源的数据进行处理

终止操作:执行中间操作链,并产生结果

 

Java8 中的 Collection 接口被扩展了,提供了两个获取流的方法:

 

default Stream stream() : 返回一个顺序流

default Stream parallelStream() : 返回一个并行流

 

List<String> list = new ArrayList<>();

Stream<String> stream = list.stream(); //获取一个顺序流

Stream<String> parallelStream = list.parallelStream(); //获取一个并行流

 

 

Java8 中的 Arrays 的静态方法 stream() 可以从数组获取流

Integer[] nums = new Integer[8];

Stream<Integer> stream = Arrays.stream(nums);

 

 

由值创建流

 

可以使用静态方法 Stream.of(), 通过显示值创建一个流。它可以接收任意数量的参数

Stream<Integer> stream = Stream.of(1,2,3,4,5);

 

由函数创建流

可以使用静态方法 Stream.iterate() 和Stream.generate(), 创建无限流。

Stream.iterate(1, (x) -> x + 1).forEach(System.out::println);

Stream.generate(() -> Math.random()).forEach(System.out::println);

 

中间操作又分四类

 

筛选

切割

映射

排序

 

filter(Predicate p), 接收Predicate实例,根据该实例的test方法进行筛选,如

 

List<Integer> list = Arrays.asList(2, 3, 5, 4, 1, 8, 10, 9, 7, 6);

    list.stream()

            .filter((e) -> e > 5)

            .forEach(System.out::println);

 

distinct(),这个方法大家应该能看出来就是去重复的,根据流所生成元素的 hashCode() 和 equals() 去除重复元素

 

List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6);

    list.stream()

            .distinct()

            .forEach(System.out::println);

 

 

切割

 

切割也有两个方法

 

limit(long maxSize),截断流,使其元素不超过给定数量,跟SQL语句很像

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);

    list.stream()

            .limit(3)

            .forEach(System.out::println);

 

skip(long n) ,返回一个去掉了前 n 个元素的流。若流中元素 

不足 n 个,则返回一个空流。

 

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);

    list.stream()

            .skip(3)

            .forEach(System.out::println);

 

可以看到这个方法刚好跟limit方法互补了,limit去尾,skip去头。

 

映射

 

map(Function f) ,接收一个Function实例,Function的抽象方法apply是接收一个参数然后返回一个值,这个返回值就是映射的结果

 

List<Integer> list = Arrays.asList(1, 2, 3);

    list.stream()

            .map(x -> x*x)

            .forEach(System.out::println);

 

mapToDouble(ToDoubleFunction f),这个函数跟map很像,只不过映射的结果一定是要Double类型

List<Integer> list = Arrays.asList(1, 2, 3);

    list.stream()

            .mapToDouble(x -> x+0.1)

            .forEach(System.out::println);

 

可以发现Integer类型的元素被映射成Double类型了

类似的还有mapToInt(ToIntFunction f)和mapToLong(ToLongFunction f)方法,这里就不去演示了。

 

List<String> list = Arrays.asList("abc", "efg", "xyz");

        list.stream()//

                .flatMap(TestStreamAPI::string2Stream)//

                .forEach(System.out::println);

 

/**

     * 接收一个字符串将其所以的字符添加到list中然后返回stream

     * @param str

     * @return

     */

    public static Stream<Character> string2Stream(String str) {

        List<Character> list = new ArrayList<>();

        char[] charArray = str.toCharArray();

        for (char c : charArray) {

            list.add(c);

        }

        return list.stream();

    }

 

其实这也不难理解,就像上面mapToDouble方法把流中的每个元素映射成一个Double类型的值一样,现在只是映射成一个Stream

 

 

排序

 

sorted(),可以将流中元素按自然顺序排序。

List<String> list = Arrays.asList("d", "a", "c");

    list.stream()

            .sorted()

            .forEach(System.out::println);

 

sorted(Comparator comp),可以将流中元素按比较器顺序排序。

List<String> list = Arrays.asList("d", "a", "c");

    list.stream()

            .sorted((x,y) -> -x.compareTo(y))

            .forEach(System.out::println);

 

终止操作

终止操作会从流的中间操作流水线生成结果。其结果可以是任何不是流的值,例如: List、 Integer,甚至是 void 。

 

其中终止操作又有三类

 

查找与匹配

归约

收集

 

查找与匹配

 

查找与匹配有下面这么多方法,我只演示几个典型的。

 

allMatch(Predicate p) 检查是否匹配所有元素

anyMatch(Predicate p) 检查是否至少匹配一个元素

noneMatch(Predicate p) 检查是否没有匹配所有元素

findFirst() 返回第一个元素

findAny() 返回当前流中的任意元素

count() 返回流中元素总数

max(Comparator c) 返回流中最大值

min(Comparator c) 返回流中最小值

forEach(Consumer c) 内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反, Stream API 使用内部迭代)

 

allMatch(Predicate p)例子

List<Integer> list = Arrays.asList(10, 5, 7, 3);

    boolean allMatch = list.stream()//

            .allMatch(x -> x > 2);//是否全部元素都大于2

    System.out.println(allMatch);

 

findFirst()例子

List<Integer> list = Arrays.asList(10, 5, 7, 3);

    Optional<Integer> first = list.stream()//

            .findFirst();

    Integer val = first.get();

    System.out.println(val);//输出10

 

max(Comparator c)例子

List<Integer> list = Arrays.asList(10, 5, 7, 3);

    Optional<Integer> first = list.stream()//

            .min(Integer::compareTo);

    Integer val = first.get();

    System.out.println(val);//输出3

 

归约

 

归约操作有下面两个方法

 

reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 T

reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 Optional

 

reduce(T iden, BinaryOperator b)例子

 

List<Integer> list = Arrays.asList(10, 5, 7, 3);

    Integer result = list.stream()

        .reduce(2, Integer::sum);

    System.out.println(result);//输出27,其实相当于2+10+5+7+3,就是一个累加

 

reduce(BinaryOperator b)例子

List<Integer> list = Arrays.asList(10, 5, 7, 3);

    Optional<Integer> optional = list.stream()

        .reduce(Integer::sum);

    Integer result = optional.get();

    System.out.println(result);//输出25,其实相当于10+5+7+3,就是一个累加

 

收集

 

collect(Collector c) 将流转换为其他形式。接收一个Collector接口的 

实现,用于给流中元素做汇总的方法

 

List<Integer> list = Arrays.asList(10, 5, 7, 3);

    // 将流中元素收集到List中

    List<Integer> resultList = list.stream()

            .collect(Collectors.toList());

 

    // 将流中元素收集到Set中

    Set<Integer> resultSet = list.stream()

            .collect(Collectors.toSet());

 

    System.out.println(resultList);// 输出[10, 5, 7, 3]

    System.out.println(resultSet);// 输出[3, 5, 7, 10]

 

上面的代码分别将流中的元素收集到List和Set中,其实还可以收集到其类型中,如Map、Optional甚至是Integer等。在收集过程中还可以做点其它操作,比如下面例子,至于其它更多的操作大家还是去看API吧

 

List<Integer> list = Arrays.asList(10, 5, 7, 3);

 

    //计算出流中的元素个数

    Long count = list.stream()//

            .collect(Collectors.counting());

    System.out.println(count);//输出4

 

    //计算流中Integer类型数据的总和

    Integer sum = list.stream()//

            .collect(Collectors.summingInt(x -> x));

    System.out.println(sum);//输出25

  

 

Stream延迟执行

上面“中间操作”那节我说到了“惰性求值”这个东西,即Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

 

 List<Person> list = Arrays.asList(//

            new Person("Jason", 18), //

            new Person("Hank", 46), //

            new Person("Alice", 23));

    // 过滤操作,找出age大于20的Person对象,但是没有终止操作

    list.stream()//

            .filter(x -> x.getAge() > 20);

运行这个测试方法,你会发现没有输出任何东西,因为它并没有终止操作,所以中间操作并未执行。下面加多一个终止操作

    List<Person> list = Arrays.asList(//

            new Person("Jason", 18), //

            new Person("Hank", 46), //

            new Person("Alice", 23));

    // 过滤操作,找出age大于20的Person对象,但是没有终止操作

    list.stream()//

            .filter(x -> x.getAge() > 20)//

            .forEach(System.out::println);

 

 

Stream API还提供了并行流,即多线程执行操作。

 

java.util.Collection<E>新添加了两个默认方法

 

default Stream stream() : 返回串行流

default Stream parallelStream() : 返回并行流

可以发现,stream()和parallelStream()方法返回的都是java.util.stream.Stream<E>类型的对象,说明它们在功能的使用上是没差别的。唯一的差别就是单线程和多线程的执行,关于Stream API还不了解的可以去我开头给出的链接那文章看看。下面我就使用一下并行流,对比串行流看看性能上的差距。

 

 

List<Integer> list = new ArrayList<>();

        // 将10000-1存入list中

        for (int i = 10000; i >= 1; i--) {

            list.add(i);

        }

 

list.stream()// 获取串行流

                .sorted()// 按自然排序,即按数字从小到大排序

                .count();// count()是终止操作,有终止操作才会执行中间操作sorted()

 

List<Integer> list = new ArrayList<>();

        // 将10000-1存入list中

        for (int i = 10000; i >= 1; i--) {

            list.add(i);

        }

 

list.parallelStream()// 获取并行流

                .sorted()// 按自然排序,即按数字从小到大排序

                .count();// count()是终止操作,有终止操作才会执行中间操作sorted()

 

from:

http://blog.csdn.net/timheath/article/details/71366448

http://blog.csdn.net/timheath/article/details/71275179

 

 

分享到:
评论

相关推荐

    【Java8】Lambda表达式 和 Stream API 详解笔记.zip

    视频地址:https://www.bilibili.com/video/BV1ut411g7E9 【Java8】Lambda表达式 和 Stream API 详解笔记 md文档

    Java 8 新特性详细介绍Lambda表达式、Stream API、接口的默认方法

    Lambda表达式、Stream API、接口的默认方法等功能极大地简化了代码的编写和阅读。新的日期/时间API和CompletableFuture等特性则提供了更好的功能支持和性能优化。通过学习和应用Java 8的新特性,开发者能够更加高效...

    Lambda表达式和StreamAPI学习总结.pdf

    Java8新特性初级入门学习

    Stream和Lambda表达式最佳实践

    Stream和Lambda表达式是Java 8引入的两个重要特性,它们极大地简化了集合处理和函数式编程的复杂性。以下是关于Stream和Lambda表达式的最佳实践介绍: Lambda表达式 Lambda表达式允许我们以简洁的方式表示匿名函数...

    06.第六节-如何精简lambda表达式.mp4

    Java8发布到现在至少3年了,但是对Lambda表达式不熟悉、看不懂、不会用的现象非常常见。 即使是升级到JDK1.8了,但是很多开发者依然是停留在1.8之前的开发方式,使用的也是非常老旧和过时的API,遇到函数式接口也是...

    SpringDemo:Java集合,Lambda表达式,Stream API和Spring Lifecycle方法的演示

    SpringDemo:Java集合,Lambda表达式,Stream API和Spring Lifecycle方法的演示

    Lambda表达式的相关用法

    Lambda and Anonymous Classes(I),展示如何使用Lambda表达式替代匿名内部类,说明Lambda表达式和函数接口的关系。 Lambda and Anonymous Classes(II),Lambda表达式的实现原理 Lambda and Collections,学习Java...

    Java8中Lambda表达式使用和Stream API详解

    主要给大家介绍了关于Java8中Lambda表达式使用和Stream API的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Java8具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

    08.第八节-使用lambda表达式创建线程.mp4

    Java8发布到现在至少3年了,但是对Lambda表达式不熟悉、看不懂、不会用的现象非常常见。 即使是升级到JDK1.8了,但是很多开发者依然是停留在1.8之前的开发方式,使用的也是非常老旧和过时的API,遇到函数式接口也是...

    10.第十节-使用lambda表达式实现排序.mp4

    Java8发布到现在至少3年了,但是对Lambda表达式不熟悉、看不懂、不会用的现象非常常见。 即使是升级到JDK1.8了,但是很多开发者依然是停留在1.8之前的开发方式,使用的也是非常老旧和过时的API,遇到函数式接口也是...

    09.第九节-使用lambda表达式遍历集合.mp4

    Java8发布到现在至少3年了,但是对Lambda表达式不熟悉、看不懂、不会用的现象非常常见。 即使是升级到JDK1.8了,但是很多开发者依然是停留在1.8之前的开发方式,使用的也是非常老旧和过时的API,遇到函数式接口也是...

    Jdk 8 lambda 表达式使用示范

    java 8 新特性lambda表达式使用DEMO,怎么使用stream api 来操作集合,collect , fiter, foreach , map等等方法的使用示范

    05.第五节-lambda表达式语法的介绍.mp4

    Java8发布到现在至少3年了,但是对Lambda表达式不熟悉、看不懂、不会用的现象非常常见。 即使是升级到JDK1.8了,但是很多开发者依然是停留在1.8之前的开发方式,使用的也是非常老旧和过时的API,遇到函数式接口也是...

    04.第四节-什么是lambda表达式概念.mp4

    Java8发布到现在至少3年了,但是对Lambda表达式不熟悉、看不懂、不会用的现象非常常见。 即使是升级到JDK1.8了,但是很多开发者依然是停留在1.8之前的开发方式,使用的也是非常老旧和过时的API,遇到函数式接口也是...

    Android 中Lambda表达式的使用实例详解

    Java8 中着实引入了一些非常有特色的功能,如Lambda表达式、streamAPI、接口默认实现等等。Lambda表达式在 Android 中最低兼容到 Android2.3 系统,兼容性还是不错的,Lambda表达式本质上是一种匿名方法,它既没有...

    深入探索Java 8 Lambda表达式

    2014年3月,Java 8发布,Lambda表达式作为一项重要的特性随之而来。或许现在你已经在使用Lambda表达式来书写简洁灵活的代码。比如,你可以使用Lambda表达式和新增的流相关的API,完成如下的大量数据的查询处理:  ...

    Java8深入学习系列(一)lambda表达式介绍

    Java8最值得学习的特性就是Lambda表达式和Stream API,所以我们学习java8的第一课就是学习lambda表达式,下面这篇文章主要给大家介绍了关于Java8学习之lambda的相关资料,文中介绍的非常详细,需要的朋友可以参考...

    《Java 8 in Action》是一本关于 Java 编程语言的书籍,重点介绍了 Java 8 中引入的新特性和改进

    Lambda 表达式: 介绍 Java 8 中引入的 Lambda 表达式,以及如何使用 Lambda 表达式来简化代码和实现函数式编程风格。 Stream API: 介绍 Java 8 中引入的 Stream API,以及如何使用 Stream API 来处理集合数据和...

    win jdk-1.8 java 基础环境

    一、Java8(JDK1.8)新特性 1、Lamdba表达式 2、函数式接口 3、方法引用和构造引用 4、Stream API 5、接口中的默认方法和静态方法 ...6、新时间日期API ...其中最为核心的是Lambda表达式和Stream API

    java8集合源码-poc-java8-lambda-stream-rxjava:poc-java8-lambda-stream-rxjava

    java8集合源码java8 lambda 流 rxjava 在 Java 8 版本中,Java 提供了对函数式编程、新的 JavaScript 引擎、用于日期时间操作的新 API、新的流 API 等的支持。 新的功能: Lambda 表达式 向 Java 添加函数处理能力。...

Global site tag (gtag.js) - Google Analytics