【java8新特性2】——Stream流

1 什么是Stream

Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。可以执行复杂的查找、过滤和映射数据等操作。Stream API 提供了一种高效且易于使用的处理数据的方式。
注意:

  1. Stream自己不会存储元素。
  2. Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream。
  3. Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

2 Stream操作的三个步骤

2.1 创建Stream

  1. 由Collection创建
    Collection接口提供了两个获取流的方法:
 default Stream<E> stream(); //返回一个顺序流
 default Stream<E> parallelStream(); //返回一个并行流
  1. 由数组创建
    Arrays 的静态方法 stream() 可以获取数组流:
 static <T> Stream<T> stream(T[] array);

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

 public static IntStream stream(int[] array);
 public static LongStream stream(long[] array);
 public static DoubleStream stream(double[] array);
  1. 由值创建
    可以使用静态方法 Stream.of(),通过显示值创建一个流。
public static<T> Stream<T> of(T... values);
  1. 由函数创建无限流
    可以使用静态方法Stream.iterate()和Stream.generate():
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f);
public static<T> Stream<T> generate(Supplier<T> s);

//例如
Stream<Integer> stream1 = Stream.iterate(0, (x) -> x + 2);//生成一个从0开始,间隔为2的无限流
Stream<Double> stream2 = Stream.generate(Math::random);//生成一个随机的无限流

2.2 中间操作

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理。而在终止操作时一次性全部处理,称为“惰性求值”

  1. 筛选与切片

Stream filter(Predicate<? super T> predicate);//接收一个断言型参数,从流中过滤某些元素

//例如
List<Employee> emps = Arrays.asList(
			new Employee("李四", 59, 6666.66),//姓名,年龄,薪资
			new Employee("张三", 18, 9999.99),
			new Employee("王五", 28, 3333.33),
			new Employee("赵六", 8, 7777.77),
			new Employee("田七", 38, 5555.55)
	);
emps.stream()	//获得流
	.filter(e -> e.getAge >= 35);	//返回年龄大于或等于35的数据

Stream distinct();//筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素

//例如
Stream<Integer> stream = Stream.of(1,2,3,3,3,3);
stream.distinct();//重复的3会被去除,返回的流中只有1,2,3三个元素。

Stream skip(long n);
Stream limit(long maxSize);
类似于SQL语句中的skip和limit,跳过n个元素,不超过maxSize个元素

//例如
emps.stream().skip(2).limit(3);//返回王五、赵六、田七三个元素
  1. 映射

Stream map(Function f);//接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。

emps.stream().map(Emp::getName);//只返回每个对象的名字

Stream flatMap(Function f);//接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流

//例如
List<String> list = new ArrayList<>();
list.add("123-456");
list.add("abc-def");
list.add("adsddf-46418");
List result = list.stream().flatMap(str -> Arrays.stream(str.split("-"))).collect(Collectors.toList());
//result的结果是[123, 456, abc, def, adsddf, 46418]
//flatMap接收的函数要求返回一个Stream,把每个stream连成一个stream

//如果使用map,返回的是三个字符串数组,如下
List result = list.stream().map(e -> e.split("-")).collect(Collectors.toList());
  1. 排序

Stream sorted();//产生一个新流,其中按自然顺序排序(字典排序)

List<String> new = result.sorted().collect(Collectors.toList());
//result: [123, 456, abc, def, adsddf, 46418]
//new: [123, 456, 46418, abc, adsddf, def]

Stream sorted(Comparator<? super T> comparator);//接收一个比较器,可以自定义排序方式。

//例如上面的emp集合,如果age一样就按name排,否则就按age排
emps.stream().sorted((e1,e2) -> {
		if(e1.getAge().equals(e2.getAge())){
			return e1.getName().compareTo(e2.getName());
		}else {
			return e1.getAge().compareTo(e2.getAge());
		}
	})

2.3 终止操作

  1. 查找与匹配

boolean allMatch(Predicate<? super T> predicate);//检查是否匹配所有元素

//例如
boolean b = emps.stream().allMatch(e -> e.getAge ==28);
//是否所有员工的年龄都是28,这里返回false

boolean anyMatch(Predicate<? super T> predicate);//检查是否至少匹配一个元素

//例如
boolean b = emps.stream().anyMatch(e -> e.getAge ==28);
//是否至少有员工的年龄是28,这里返回true

boolean noneMatch(Predicate<? super T> predicate);//检查是否没有匹配所有元素

//例如
boolean b = emps.stream().noneMatch(e -> e.getAge ==28);
//是否所有有员工的年龄都不是28,这里返回false

Optional findFirst();//返回第一个元素
Optional findAny();//返回当前流中的任意元素
Optional min(Comparator<? super T> comparator);//返回流中最小值
Optional max(Comparator<? super T> comparator);//返回流中最大值

返回的是一个optional对象,需要调用get()方法获取对应的T对象。Optional是java8用来避免空指针的, 下次我们再说。

//例如
Optional<Emp> optional = emps.stream().findFirst();
Emp emp = optional.get();

long count();//返回流中元素总数

  1. 归约

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

//例如
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer sum = list.stream().reduce(0, (x,y) -> x+y);
//起始值为0,将流中元素反复相加,sum = 55

Optional reduce(BinaryOperator accumulator);//返回Optional

Optional<Double> op = emps.stream().map(Employee::getSalary).reduce(Double::sum);
Double sum = op.get();
//因为没有给初始值,返回值可能为空,所以返回的是Optional对象
  1. 收集

<R, A> R collect(Collector<? super T, A, R> collector);//将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法。
Collectors 实用类提供了很多静态方法,可以方便地创建常见Collector实例,如:

emps.stream().collect(Collectors.toList());//把流中元素收集到List

emps.stream().collect(Collectors.toSet());//把流中元素收集到Set

emps.stream().collect(Collectors.toCollection(ArrayList::new));//把流中元素收集到创建的集合

long count = emps.stream().collect(Collectors.counting());//计算流中元素的个数

int total = emps.stream().collect(Collectors.summingInt(Employee::getSalary));//对流中元素的整数属性求和

double avg= emps.stream().collect(Collectors.averagingInt(Employee::getSalary));//计算流中元素的整数属性的平均值

//收集流中元素的整数属性的统计值。包括count、sum、min、max、average。
IntSummaryStatistics iss = emps.stream().collect(Collectors.summarizingInt(Employee::getSalary));

String str= emps.stream().map(Employee::getName).collect(Collectors.joining());//连接流中每个字符串
//输出"李四张三王五赵六田七"
String str= emps.stream().map(Employee::getName).collect(Collectors.joining(","));//连接流中每个字符串
//输出"李四,张三,王五,赵六,田七"

Optional<Employee> max = list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));//根据比较器选择最大值

//根据属性值对流进行分组,属性值为键。
Map<Emp.Status, List<Employee>> map = list.stream().collect(Collectors.groupingBy(Employee::getStatus));

//根据true或false进行分区
Map<Boolean,List<Emp>> vd = list.stream().collect(Collectors.partitioningBy(e -> e.getSalary > 5000));
//根据薪资是否大于5000进行分区

3 并行流

3.1 什么是并行流

并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。并行流的底层其实就是ForkJoin框架的一个实现。
Java8中将并行流进行了优化,我们可以很容易的对数据进行并行操作。Stream API可以声明性地通过parallel()与scqucntial()在并行流与顺序流之间进行切换。

3.2 ForkJoin框架

Fork/Join框架:在必要的情况下,将一个大任务,进行拆分(fork) 成若干个子任务(拆到不能再拆,这里就是指我们制定的拆分的临界值),再将一个个小任务的结果进行join汇总。
在这里插入图片描述
Fork/Join采用“工作窃取模式”,当执行新的任务时他可以将其拆分成更小的任务执行,并将小任务加到线程队列中。完成自己的工作而处于空闲的工作线程能够从其他仍处于忙碌(busy)状态的工作线程中窃取等待任务执行,每个工作线程都有自己的工作队列,这是使用双端队列(deque)来实现的。当一个任务划分一个新线程时,它将自己推到deque的头部。当线程的任务队列为空,它将尝试从另一个线程的deque的尾部窃取另一个任务。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值