一、为什么需要用Stream?
Java8 中的Stream API 它与Java.io包里的InputStream 和 OutputStream 是完全不同的概念,也不同于StAX对XML解析的Stream。
它提供了一种高效且易于使用的处理数据的方式,是对集合(Collection)对象功能的增强。
它可以指定对集合的操作,可以执行非常复杂的查找、过滤、映射数据等操作。
使用Stream API 对集合数据进行操作,就类似于SQL执行的数据查询。也可以使用Stream API 来并行执行操作。
二、什么是Stream?
流(Stream)是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。集合讲的是数据,流讲的是计算。
注意:
①Stream 自己不会存储元素;
②Stream 返回一个新结果的数据Stream,而对源对象不会产生影响;
③Stream 操作是延迟执行的,这意味着它会等到需要结果的时候 才全部执行,
(中间操作:不会进行任何操作;终止操作:一次性执行全部内容,即“惰性求值”)
三、如何操作Stream?
Java8中的Collection接口被扩展,提供了两个获取流的方法:
* default Stream<E> stream() 返回一个顺序流
* default Stream<E> parallelStream() 返回一个并行流
1、 创建 Stream
//创建Stream
@Test
public void test1(){
//1. 可以通过 Collection 系列集合提供的 Stream() 或 parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//2、通过Arrays 中的静态方法 stream()获取数组流
Employee[] emps = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(emps);
//3.通过Stream类中的静态方法of()
Stream<String> stream3 = Stream.of("aa", "bb", "cc");
//4.创建无线流
//迭代
Stream<Integer> stream4 = Stream.iterate(0, (e) -> e+2);
stream4.limit(10).forEach(System.out::println);
System.out.println("====================");
//生成
Stream.generate(() -> (int)(Math.random() * 100)).limit(5).forEach(System.out::println);
}
2、 中间操作
筛选与切片
filter —— 接收Lambda,从流中排除某些元素;
limit —— 截断流,使其元素不超过给定数量;
skip(n) —— 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit互补。
distinct —— 筛选,通过流所生成元素的hasCode() 和 equals() 去除重复元素
@Test
public void test1(){
//中间操作: 不会执行任何操作
Stream<Employee> stream = emp.stream()
.filter((e) -> {
System.out.println("Stream API的中间操作");
return e.getAge() > 35;
});
//终止操作: 一次性执行全部内容,即“惰性求值”
stream.forEach(System.out::println);
}
@Test
public void test2(){
emp.stream().filter((e) -> {
System.out.println("短路!");
return e.getSalary() < 4000;
}).limit(2).forEach(System.out::println);
}
@Test
public void test3(){
emp.stream().filter((e) -> {
System.out.println("短路!");
return e.getSalary() > 3000;
}).skip(2).distinct().forEach(System.out::println);
}
3、映射 map——接收一个lambda表达式,将元素映射成其他元素或提取信息。接收一个函数作为参数 ,该函数会被每个元素应用,并将其映射成一个新元素。
flatMap——接收一个函数作为参数,将流中每个值都换成另外一个流,然后把所有流连接成一个流。
@Test
public void test4(){
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
list.stream()
.map((str) -> str.toUpperCase())
.forEach(System.out::println);
System.out.println("-------------------");
emp.stream()
.map(Employee::getName)
.forEach(System.out::println);
System.out.println("--------------------------------------------");
Stream<Stream<Character>> stream = list.stream().map(StreamTest2::filterChar); //每个map都会映射成一个Stream
stream.forEach((sm) -> {
sm.forEach(System.out::println);
});
System.out.println("-------------------");
Stream<Character> stream2 = list.stream().flatMap(StreamTest2::filterChar);
stream2.forEach(System.out::println);
}
public static Stream<Character> filterChar(String str){
List<Character> list = new ArrayList<>();
for (Character ch : str.toCharArray()) {
list.add(ch);
}
return list.stream();
}
4、排序 sorted() 产生一个新流,其中按自然顺序排序
sorted(Comparator com) 产生一个新流,其中按比较器自定顺序排序
@Test
public void test5(){
List<String> list = Arrays.asList("ccc", "aaa", "bbb", "eee", "ddd");
list.stream()
.sorted()
.forEach(System.out::println);
System.out.println("--------------------");
emp.stream()
.sorted((e1, e2) -> {
if (e1.getAge() == e2.getAge()) {
return e1.getName().compareTo(e2.getName());
}else{
return e1.getAge().compareTo(e2.getAge());
}
}).forEach(System.out::println);
}