【转载】Java8特性:Stream基础语法学习以及训练实例

原文链接:Java 8系列之Stream的基本语法详解(若有侵权,请私聊我删除哦,谢谢)

一、Stream的介绍

聚合操作是Java 8针对集合类,使编程更为便利的方式,可以与Lambda表达式一起使用,达到更加简洁的目的。

对Stream聚合操作可以总结为以下三个步骤:

  1. 创建Stream:通过stream()方法,取得集合对象的数据集。
  2. Intermediate:通过一系列中间(Intermediate)方法,对数据集进行过滤、检索等数据集的再次处理。
  3. Terminal通过最终(terminal)方法完成对数据集中元素的处理。

在一次聚合操作中,可以有多个Intermediate,但是有且只有一个Terminal。也就是说,在对一个Stream可以进行多次转换操作,并不是每次都对Stream的每个元素执行转换。并不像for循环中,循环N次,其时间复杂度就是N。转换操作是lazy(惰性求值)的,只有在Terminal操作执行时,才会一次性执行。可以这么认为,Stream 里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,在 Terminal 操作的时候循环 Stream 对应的集合,然后对每个元素执行所有的函数。

二、Stream操作的分类

Stream的操作有Intermediate、Terminal和Short-circuiting:

  • Intermediate:map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 skip、 parallel、 sequential、 unordered

  • Terminal:forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、iterator

  • Short-circuiting:anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit

三、创建Stream的方式

我们有多种方式生成Stream:

  1. Stream接口的静态工厂方法(注意:Java8里接口可以带静态方法)
    of()
    generator()
    iterate()
    empty()

  2. Collection接口和数组的默认方法(默认方法,也使Java的新特性之一,后续介绍),把一个Collection对象转换成Stream

  3. 其他方式
    Random.ints()
    BitSet.stream()
    Pattern.splitAsStream(java.lang.CharSequence)
    JarFile.stream()

3.1 静态工厂方式

of
of方法,其生成的Stream是有限长度的,Stream的长度为其内的元素个数。
示例:

Stream<Integer> integerStream = Stream.of(1, 2, 3);
Stream<String> stringStream = Stream.of("A");

generator
generator方法,返回一个无限长度的Stream,其元素由Supplier接口的提供。(Supplier是一个函数接口,只封装了一个get()方法,其用来返回任何泛型的值,该结果在不同的时间内,返回的可能相同也可能不相同,没有特殊的要求)
示例:

//一般无限长度的Stream会与filter、limit等配合使用,否则Stream会无限制的执行下去
Stream<Double> generateB = Stream.generate(()-> java.lang.Math.random());

iterate
iterate方法,其返回的也是一个无限长度的Stream,与generate方法不同的是,其是通过函数f迭代对给指定的元素种子而产生无限连续有序Stream,其中包含的元素可以认为是:seed,f(seed),f(f(seed))无限循环。
示例:

Stream.iterate(1, item -> item + 1)
        .limit(10)
        .forEach(System.out::println); 
        // 打印结果:1,2,3,4,5,6,7,8,9,10

empty
empty方法返回一个空的顺序Stream,该Stream里面不包含元素项。

3.2 Collection接口和数组的静态方法

对于Collection接口实现的各种类,通过以下方法获取Stream实例:

stream()方法,如:
List.stream()获取stream实例。

对于数组,通过以下方法获取Stream实例:

int ids = new int[]{1,2};
Arrays.stream(ids); // 获取实例

3.3 其他方法

Random.ints()
BitSet.stream()
Pattern.splitAsStream(java.lang.CharSequence)
JarFile.stream()

四、中间操作

  1. concat
    concat方法将两个Stream连接在一起,合成一个Stream。
    若两个输入的Stream都是排序的,则新Stream也是排序的;若输入的Stream中任何一个是并行的,则新的Stream也是并行的;若关闭新的Stream时,原两个输入的Stream都将执行关闭处理。
    示例:
Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 5))
       .forEach(integer -> System.out.print(integer + "  "));
// 打印结果
// 1  2  3  4  5  
  1. distinct
    distinct方法以达到去除掉原Stream中重复的元素,生成的新Stream中没有没有重复的元素。
    示例:
Stream.of(1,2,3,1,2,3)
        .distinct()
        .forEach(System.out::println); // 打印结果:1,2,3
  1. filter
    filter方法对原Stream按照指定条件过滤,在新建的Stream中,只包含满足条件的元素,将不满足条件的元素过滤掉。
    示例:
Stream.of(1, 2, 3, 4, 5)
        .filter(item -> item > 3)		// 参数为Predicate
        .forEach(System.out::println);// 打印结果:4,5
  1. map
    map方法将对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。
    示例:
Stream.of("a", "b", "hello")
        .map(item-> item.toUpperCase())		// 参数为Function
        .forEach(System.out::println);
        // 打印结果
        // A, B, HELLO
  1. flatMap
    flatMap方法与map方法类似,都是将原Stream中的每一个元素通过转换函数转换,不同的是,该换转函数的对象是一个Stream,也不会再创建一个新的Stream,而是将原Stream的元素取代为转换的Stream。
    示例:
Stream.of(1, 2, 3)
    .flatMap(integer -> Stream.of(integer * 10))	// 参数为Function
    .forEach(System.out::println);
    // 打印结果
    // 10,20,30
  1. peek
    peek方法生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数(Consumer实例),新Stream每个元素被消费的时候都会执行给定的消费函数,并且消费函数优先执行
    示例:
Stream.of(1, 2, 3, 4, 5)
        .peek(integer -> System.out.println("accept:" + integer)) // 参数为Consumer
        .forEach(System.out::println);
// 打印结果
// accept:1
//  1
//  accept:2
//  2
//  accept:3
//  3
//  accept:4
//  4
//  accept:5
//  5
  1. skip
    skip方法将过滤掉原Stream中的前N个元素,返回剩下的元素所组成的新Stream。如果原Stream的元素个数大于N,将返回原Stream的后(原Stream长度-N)个元素所组成的新Stream;如果原Stream的元素个数小于或等于N,将返回一个空Stream。
    示例:
Stream.of(1, 2, 3,4,5)
	.skip(2)
	.forEach(System.out::println);
// 打印结果
// 3,4,5
  1. sorted
    sorted方法将对原Stream进行排序,返回一个有序列的新Stream。sorterd有两种变体sorted(),sorted(Comparator),前者将默认使用Object.equals(Object)进行排序,而后者接受一个自定义排序规则函数(Comparator),可按照意愿排序。
    示例:
Stream.of(5, 4, 3, 2, 1)
        .sorted()
        .forEach(System.out::println);
        // 打印结果
        // 1,2,3,4,5

五、终止操作

  1. collect
    Java 8系列之Stream的强大工具Collector
    Java 8系列之重构和定制收集器
  2. count
    count方法将返回Stream中元素的个数。
    示例:
long count = Stream.of(1, 2, 3, 4, 5)
        .count();
System.out.println("count:" + count);// 打印结果:count:5
  1. forEach
    循环遍历。
    示例:
Stream.of(5, 4, 3, 2, 1)
    .sorted()
    .forEach(System.out::println);
    // 打印结果
    // 1,2,3,4,5
  1. forEachOrdered
    forEachOrdered方法与forEach类似,都是遍历Stream中的所有元素,不同的是,如果该Stream预先设定了顺序,会按照预先设定的顺序执行(Stream是无序的),默认为元素插入的顺序。
    示例:
Stream.of(5,2,1,4,3)
        .forEachOrdered(integer -> {
            System.out.println("integer:"+integer);
        }); 
// 打印结果
// integer:5
// integer:2
// integer:1
// integer:4
// integer:3
  1. max
    max方法根据指定的Comparator,返回一个Optional,该Optional中的value值就是Stream中最大的元素。
    其中注意max返回的是一个Optional。
    示例:
Optional<Integer> max = Stream.of(1, 2, 3, 4, 5)
        .max((o1, o2) -> o2 - o1);	// 自行指定Comparator
System.out.println("max:" + max.get());// 打印结果:max:1
  1. min
    min方法根据指定的Comparator,返回一个Optional,该Optional中的value值就是Stream中最小的元素。
    示例:
Optional<Integer> max = Stream.of(1, 2, 3, 4, 5)
        .max((o1, o2) -> o1 - o2);
System.out.println("max:" + max.get());// 打印结果:min:5
  1. reduce
    Java 8系列之Stream中万能的reduce

六、Short-circuiting

  1. allMatch
    allMatch操作用于判断Stream中的元素是否全部满足指定条件。如果全部满足条件返回true,否则返回false。
    示例:
boolean allMatch = Stream.of(1, 2, 3, 4)
    .allMatch(integer -> integer > 0);
System.out.println("allMatch: " + allMatch); // 打印结果:allMatch: true 
  1. anyMatch
    anyMatch操作用于判断Stream中的是否有满足指定条件的元素。如果最少有一个满足条件返回true,否则返回false。
    示例:
boolean anyMatch = Stream.of(1, 2, 3, 4)
    .anyMatch(integer -> integer > 3);
System.out.println("anyMatch: " + anyMatch); // 打印结果:anyMatch: true 
  1. findAny
    findAny操作用于获取含有Stream中的某个元素的Optional,如果Stream为空,则返回一个空的Optional。由于此操作的行动是不确定的,其会自由的选择Stream中的任何元素。在并行操作中,在同一个Stram中多次调用,可能会不同的结果。在串行调用时,Debug了几次,发现每次都是获取的第一个元素,个人感觉在串行调用时,应该默认的是获取第一个元素。
    示例:
Optional<Integer> any = Stream.of(1, 2, 3, 4).findAny();
  1. findFirst
    findFirst操作用于获取含有Stream中的第一个元素的Optional,如果Stream为空,则返回一个空的Optional。若Stream并未排序,可能返回含有Stream中任意元素的Optional。
  2. limit
    limit方法将截取原Stream,截取后Stream的最大长度不能超过指定值N。如果原Stream的元素个数大于N,将截取原Stream的前N个元素;如果原Stream的元素个数小于或等于N,将截取原Stream中的所有元素。
    示例:
Stream.of(1, 2, 3,4,5)
        .limit(2)
        .forEach(System.out::println);
        // 打印结果
        // 1,2
  1. noneMatch
    noneMatch方法将判断Stream中的所有元素是否满足指定的条件,如果所有元素都不满足条件,返回true;否则,返回false。
boolean noneMatch = Stream.of(1, 2, 3, 4, 5)
    .noneMatch(integer -> integer > 10);
System.out.println("noneMatch:" + noneMatch); // 打印结果 noneMatch:true

七、训练实例

原文链接:Java8 Stream:2万字20个实例,玩转集合的筛选、归约、分组、聚合
(若有侵权,请私聊我删除哦,谢谢)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值