流(Stream)的含义

是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。

集合讲的是数据,流讲的是计算

注意:

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


Stream的操作三个步骤

  1. 创建Stream:一个数据源(如:集合、数组),获取一个流
  2. 中间操作:一个中间操作链,对数据源的数据进行处理
  3. 终止操作:一个终止操作,执行中间操作链,并产生结果




简单示例

@Test
public void test1() {
// 1.0 可以通过Collection系列集合提供的stream() 或 parallelStream()
List<String> list = new ArrayList<String>();
Stream<String> stream1 = list.stream();

// 2.0 通过Arrays中的静态方法stream()获取数组流
Emp[] empArr = new Emp[10];
Stream<Emp> stream2 = Arrays.stream(empArr);

// 3.0 通过Stream类中的静态方法of()
Stream<String> stream3 = Stream.of("aa", "bb", "cc");

// 4.0 创建无限流
// 迭代
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x+2);
stream4.limit(10).forEach(System.out::println);

// 生成
Stream.generate(() -> Math.random())
.limit(10)
.forEach(System.out::println);

}



筛选与切片

filter 接收Lambda,从流中排出某些元素
limit 截断流,使其元素不超过给定数量
skip 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与Limit(n)互补
distinct 筛选,通过流所生成元素的hashCode()和equals()去除重复元素

package java8.Stream;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;

import org.junit.Test;

import java8.Lambda.Emp;

/**
* Java8 Stream
*
* 一、Stream的三个操作步骤:
* 1. 创建Stream
* 2. 中间操作
* 3. 终止操作(终端操作)
*/

public class TestStream2 {

List<Emp> empList = Arrays.asList(
new Emp("张三", 18, 2000),
new Emp("李四", 20, 3000),
new Emp("王五", 25, 4000),
new Emp("赵六", 30, 5000),
new Emp("田七", 35, 6000),
new Emp("田七", 35, 6000),
new Emp("田七", 35, 6000)
);


@Test
public void test1() {
Stream<Emp> stream = empList.stream()
.filter((e) -> {
System.out.println("Stream API的中间操作");
return e.getAge() > 18;
}); // 中间操作不会有任何结果

// 终止操作:一次性执行全部内容,即"惰性求值"
stream.forEach(System.out::println);
}

@Test
public void test2() {
empList.stream()
.filter((e) -> {
System.out.println("短路!");
return e.getSalary() > 2000;
})
.limit(3)
.forEach(System.out::println);
}

@Test
public void test3() {
empList.stream()
.filter((e) -> e.getSalary() > 2000)
.skip(2)
.forEach(System.out::println);
}

@Test
public void test4() {
empList.stream()
.filter((e) -> e.getSalary() > 2000)
.skip(2)
.distinct() // Emp必须重写hashCode()和equals()
.forEach(System.out::println);
}
}



映射

map 接收一个Lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
flatMap 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流

private static Stream<Character> filterCharacter(String str) {
List<Character> list = new ArrayList<Character>();
for (Character ch : str.toCharArray()) {
list.add(ch);
}
return list.stream();
}

@Test
public void test5() {
List<String> list = Arrays.asList("aa", "bb", "cc", "dd", "ee");
list.stream()
.map((str) -> str.toUpperCase())
.forEach(System.out::println);

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

empList.stream()
.map(Emp::getName)
.forEach(System.out::println);

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

Stream<Stream<Character>> streamStream = list.stream()
.map(TestStream2::filterCharacter); // {{a,a},{b,b},{c,c},{d,d},{e,e}}

streamStream.forEach((sm) -> {
sm.forEach(System.out::println);
});

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

// flatMap
list.stream()
.flatMap(TestStream2::filterCharacter) // {a,a,b,b,c,c,d,d,e,e}
.forEach(System.out::println);

}



排序

 sorted() 自然排序(Comparable)
sorted(Comparator com) 定制排序(Comparator)


@Test
public void test6() {
List<String> list3 = Arrays.asList("cc", "aa", "bb", "dd", "ee");
list3.stream()
.sorted()
.forEach(System.out::println);

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

empList.stream()
.sorted((e1, e2) -> {
if (e1.getAge().equals(e2.getAge())) {
return e1.getName().compareTo(e2.getName());
} else {
return e1.getAge().compareTo(e2.getAge());
}
}).forEach(System.out::println);
}



查找与匹配

allMatch 检查是否匹配所有元素
anyMatch 检查是否至少匹配一个元素
noneMatch 检查是否没有匹配元素
findFirst 返回第一个元素
findAny 返回当前流中的任意元素
count 返回流中元素的总个数
max 返回流中最大值
min 返回流中最小值

package java8.Stream;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import org.junit.Test;

import java8.Lambda.Emp;

public class TestStream3 {

List<Emp> empList = Arrays.asList(
new Emp("张三", 18, 19999, Emp.Status.FREE),
new Emp("李四", 28, 29999, Emp.Status.BUSY),
new Emp("王五", 38, 39999, Emp.Status.VOCATION),
new Emp("赵六", 16, 17999, Emp.Status.BUSY),
new Emp("田七", 6, 12999, Emp.Status.FREE)
);

@Test
public void test1() {
boolean b1 = empList.stream()
.allMatch((e) -> e.getStatus().equals(Emp.Status.BUSY));
System.out.println(b1);

boolean b2 = empList.stream()
.anyMatch((e) -> e.getStatus().equals(Emp.Status.BUSY));
System.out.println(b2);

boolean b3 = empList.stream()
.noneMatch((e) -> e.getStatus().equals(Emp.Status.FREE));
System.out.println(b3);

Optional<Emp> op = empList.stream()
.sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
.findFirst();
System.out.println(op.get());

Optional<Emp> op2 = empList.parallelStream()
.filter((e) -> e.getStatus().equals(Emp.Status.FREE))
.findAny();
System.out.println(op2.get());

Long count = empList.stream().count();
System.out.println(count);

Optional<Emp> op3 = empList.stream()
.max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(op3.get());

Optional<Integer> op4 = empList.stream()
.map((Emp::getSalary))
.min(Double::compare);
System.out.println(op4.get());
}

}



规约

reduce 可以将流中元素反复结合起来,得到一个值

@Test
public void test2() {
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);
System.out.println(sum);

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

Optional<Integer> op = empList.stream() //可能为空 所有返回的是Optional
.map(Emp::getSalary)
.reduce(Integer::sum);
System.out.println(op.get());
}



收集

collect 将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法

@Test
public void test3() {
List<String> list = empList.stream()
.map(Emp::getName)
.collect(Collectors.toList());
list.forEach(System.out::println);

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

Set<String> set = empList.stream()
.map(Emp::getName)
.collect(Collectors.toSet());
set.forEach(System.out::println);

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

HashSet<String> hs = empList.stream()
.map(Emp::getName)
.collect(Collectors.toCollection(HashSet::new));
hs.forEach(System.out::println);
}

@Test
public void test4() {
//总数
Long count = empList.stream()
.collect(Collectors.counting());
System.out.println(count);

//平均值
Double avg = empList.stream()
.collect(Collectors.averagingDouble(Emp::getSalary));
System.out.println(avg);

//总和
Double sumSalary = empList.stream()
.collect(Collectors.summingDouble(Emp::getSalary));
System.out.println(sumSalary);

//最大值
Optional<Emp> max = empList.stream()
.collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(max.get());

//最小值
Optional<Integer> min = empList.stream()
.map(Emp::getSalary)
.collect(Collectors.minBy(Integer::compare));
System.out.println(min.get());

//分组
Map<Emp.Status, List<Emp>> map = empList.stream()
.collect(Collectors.groupingBy(Emp::getStatus));
System.out.println(map);

//多级分组
Map<Emp.Status, Map<String, List<Emp>>> mapMap = empList.stream()
.collect(Collectors.groupingBy(Emp::getStatus, Collectors.groupingBy((e) -> {
if (((Emp)e).getAge() <= 18) {
return "dud";
} else if(((Emp)e).getAge() <= 30) {
return "heh";
} else {
return "hah";
}
})));
System.out.println(mapMap);

//分片(分区)
Map<Boolean, List<Emp>> booleanListMap = empList.stream()
.collect(Collectors.partitioningBy((e) -> e.getSalary() > 13000));
System.out.println(booleanListMap);

//其他
DoubleSummaryStatistics dss = empList.stream()
.collect(Collectors.summarizingDouble(Emp::getSalary));
System.out.println(dss.getSum());

String str = empList.stream()
.map(Emp::getName)
.collect(Collectors.joining());
System.out.println(str);
}


回到顶部