stream流去除对象的值_Java8中的流处理Stream API

1. 是什么Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对

集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。

使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数

据库查询。也可以使用 Stream API 来并行执行操作。简而言之,

Stream API 提供了一种高效且易于使用的处理数据的方式。

注意:Stream 自己不会存储元素。

Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

2. Stream 的使用

三步骤创建 Stream

一个数据源(如: 集合、数组), 获取一个流

中间操作

一个中间操作链,对数据源的数据进行处理终止操作(终端操作)

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

2.1 创建StreamCollection 提供了两个方法 stream() 与 parallelStream()List list = new ArrayList<>();

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

Stream parallelStream = list.parallelStream(); //获取一个并行流Java8 中的 Arrays 的静态方法 stream() 可以获取数组流Integer[] nums = new Integer[10];

Stream stream1 = Arrays.stream(nums);

#还有很多重载方法也可以获得流

重载形式,能够处理对应基本类型的数组:

public static IntStream stream(int[] array)

public static LongStream stream(long[] array)

public static DoubleStream stream(double[] array)通过concat方法让多个流合并List carts = queryCartList();

List carts2 = queryCartList();

Stream concat = Stream.concat(carts.stream(), carts2.stream());

#然后可以接着操作流。通过 Stream 类中静态方法 of()Stream stream2 = Stream.of(1,2,3,4,5,6);由函数创建流:创建无限流

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

Stream stream3 = Stream.iterate(0, (x) -> x + 2).limit(10);

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

//生成

Stream stream4 = Stream.generate(Math::random).limit(2);

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

2.2 中间操作

tips:当没使用显式的使用Iterator进行遍历时,称为内部迭代,使用Strea内部完成。

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”.2.2.1 筛选与切片filter(Predicate p) —— 接收 Lambda , 从流中排除某些元素。Stream stream = emps.stream()

.filter((e) -> {

System.out.println("测试中间操作");

return e.getAge() <= 35;

});limit—— 截断流,使其元素不超过给定数量。#相当于短路,当到达数量后就不再进行其他操作

emps.stream()

.filter((e) -> {

System.out.println("短路!"); // && ||

return e.getSalary() >= 5000;

}).limit(3)

.forEach(System.out::println);skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补emps.parallelStream()

.filter((e) -> e.getSalary() >= 5000)

.skip(2)

.forEach(System.out::println);distinct—— 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素emps.stream()

.distinct()

.forEach(System.out::println);2.2.2 映射map——接收 Lambda , 将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。List strList = Arrays.asList("aaa", "bbb", "ccc", "ddd");

Stream stream = strList.stream()

.map(String::toUpperCase);

stream.forEach(System.out::println);flatMap——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。# 这里给出一个案例,需求是把字符串集合的每个字符分开变成单个字节然后输出。map实现的是每个字符串生成流,然后返回流的集合。而flatMap是把所有的流中的元素放在一个流中。通过函数的返回值可以清晰的看出来区别。

public void test1(){

List strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");

Stream> stream2 = strList.stream()

// .map(TestStreamAPI1::filterCharacter);

.map((e) -> filterCharacter(e));

stream2.forEach((sm) -> {

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

});

System.out.println("-------------------------------------");

Stream stream3 = strList.stream()

.flatMap(TestStreamAPI1::filterCharacter);

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

}

public static Stream filterCharacter(String str){

List list = new ArrayList<>();

for (Character ch : str.toCharArray()) {

list.add(ch);

}

return list.stream();

}这两个还有很多子类型:

mapToDouble(ToDoubleFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。

mapToInt(ToIntFunction f)

mapToLong(ToIntFunction f)

flatMap也有同样的三种方法。这里不再细说。2.2.3 排序sorted()——自然排序emps.stream()

.map(Employee::getName)

.sorted()

.forEach(System.out::println);sorted(Comparator com)——定制排序emps.stream()

.sorted((x, y) -> {

if(x.getAge() == y.getAge()){

return x.getName().compareTo(y.getName());

}else{

return Integer.compare(x.getAge(), y.getAge());

}

}).forEach(System.out::println);2.2.4 range操作range和rangeClosed

range不包括范围中的后面的数,而rangeClosed包括后面的数。public class RangeTest {

public static void main(String[] args) {

IntStream.range(0,10).forEach(System.out::print);

System.out.println("==============");

IntStream.rangeClosed(0,10).forEach(System.out::print);

}

}

// 输出: 0123456789==============

//012345678910

2.3 终止操作

注意:流进行了终止操作后,不能再次使用

**终止操作会从流的流水线生成结果。其结果可以是任何不是流的

值,例如: List、 Integer,甚至是 void 。**2.3.1 查找与匹配allMatch——检查是否匹配所有元素boolean bl = emps.stream()

.allMatch((e) -> e.getStatus().equals(Status.BUSY));

System.out.println(bl);anyMatch——检查是否至少匹配一个元素boolean bl1 = emps.stream()

.anyMatch((e) -> e.getStatus().equals(Status.BUSY));

System.out.println(bl1);noneMatch——检查是否没有匹配的元素boolean bl2 = emps.stream()

.noneMatch((e) -> e.getStatus().equals(Status.BUSY));

System.out.println(bl2);findFirst——返回第一个元素Optional op = emps.stream()

.sorted((e1, e2) ->

Double.compare(e1.getSalary(), e2.getSalary()))

.findFirst();

System.out.println(op.get());findAny——返回当前流中的任意元素Optional op2 = emps.parallelStream()

.filter((e) -> e.getStatus().equals(Status.FREE))

.findAny();

System.out.println(op2.get());count——返回流中元素的总个数long count = emps.stream()

.filter((e) -> e.getStatus().equals(Status.FREE))

.count();

System.out.println(count);max——返回流中最大值Optional op = emps.stream()

.map(Employee::getSalary)

.max(Double::compare);min——返回流中最小值Optional op2 = emps.stream()

.min((e1, e2) ->

Double.compare(e1.getSalary(), e2.getSalary()));2.3.2 规约reduce(T identity, BinaryOperator) `可以将流中元素反复结合起来,得到一个值。

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

返回 Optional`List list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);

#方式一,会把这个o当做初始的x然后进行操作。

Integer sum = list.stream()

.reduce(0, (x, y) -> x + y);

System.out.println(sum);

# 方式二

Optional op = emps.stream()

.map(Employee::getSalary)

.reduce(Double::sum);

System.out.println(op.get());

map 和 reduce 的连接通常称为 map-reduce 模式2.3.3 收集collect(Collector c) 将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法

其中toMap的时候可以指定键冲突时候的策略Map collect = Stream.concat(list.stream(), frontCartItems.stream())

.collect(Collectors

.toMap(CartItemSku::getSkuId, val -> val, (oldValue, newValue) -> {

oldValue.setQuantity(oldValue.getQuantity() + newValue.getQuantity());

return oldValue;

}));

Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、 Set、 Map)。但是 Collectors 类提供了很多静态方法,可以方便地创建常见收集器实例,具体使用如下图:

3.并行流和串行流

3.1. 简介并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。

Java 8 中将并行进行了优化,我们可以很容易的对数据进行并行操作。 Stream API 可以声明性地通过 parallel() 与sequential() 在并行流与顺序流之间进行切换。

3.2. 了解 Fork/Join 框架Fork/Join 框架: 就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行 join 汇总.

Fork/Join 框架与传统线程池的区别:采用 “工作窃取”模式( work-stealing):

当执行新的任务时它可以将其拆分分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。相对于一般的线程池实现,fork/join框架的优势体现在对其中包含的任务的处理方式上.在一般的线程池中,如果一个线程正在执行的任务由于某些原因无法继续运行,那么该线程会处于等待状态.而在fork/join框架实现中,如果某个子问题由于等待另外一个子问题的完成而无法继续运行.那么处理该子问题的线程会主动寻找其他尚未运行的子问题来执行.这种方式减少了线程的等待时间,提高了性能。

3.3. 使用

java8中的并行流底层使用的就是Fork/Join 模式。long start = System.currentTimeMillis();

Long sum = LongStream.rangeClosed(0L, 10000000000L)

.parallel()

.sum();

System.out.println(sum);

long end = System.currentTimeMillis();

System.out.println("耗费的时间为: " + (end - start));

4 总结

Stream API 的功能可以说非常强大,学会是在练习的基础之上,所以勤联系才能提升。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值