简介
Stream流 是 JDK1.8
加入的新特性,Stream流跟I/O流不同,Stream流用于操作数据源(集合、数组等)所生成的元素序列。
Stream 有几个特点:
- 它不会存储元素
- 延迟执行,Stream 会等到需要结果时才会执行
- 不会改变数据源(使用map方法可以通过对象引用还改变源数据)
- 对 Stream 的操作是以 lamnda 表达式为参数的
- 可以是无限的,用 Stream 可以轻松表示全体自然数,这是集合类不可能做到的。
- stream的聚合、消费或收集操作只能进行一次,再次操作会报错,Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了
使用 Stream 有三个步骤:
- 创建一个Stream流
- 中间操作
- 终止操作
创建
// 1. 通过Collections系列集合提供的stream() 或 parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream01 = list.stream();
// 2. 通过Arrays中的静态方法stream()获取数组流
String[] strList = new String[10];
Stream<String> stream02 = Arrays.stream(strList);
// 3. 通过Stream类中的静态方法
Stream<String> stream03 = Stream.of(strList);
// 4. 迭代
Stream<Integer> stream04 = Stream.iterate(0, (x) -> (x + 1));
stream04.limit(10).forEach(System.out::println);
// 5. 生成
Stream<Double> stream05 = Stream.generate(() -> Math.random());
stream05.limit(10).forEach(System.out::println);
中间操作
数据源:
List<Human> list = new ArrayList<>();
list.add(new Human("小王", 31, "男"));
list.add(new Human("小黑", 24, "女"));
list.add(new Human("小张", 10, "男"));
list.add(new Human("胖虎", 15, "男"));
list.add(new Human("小王", 31, "男"));
list.add(new Human("胖虎", 15, "男"));
获取Stream
Stream<Human> stream = list.stream();
过滤,获取大于二十岁的:
stream.filter(item -> item.getAge() > 20).forEach(System.out::println);
切片,利用skip
跟limit
方法 配合使用实现切片
// 切片,获取下标 [2,4) 的元素
stream.skip(2).limit(3).forEach(System.out::println);
映射,将函数作用在流的每个元素上
// 所有人年龄加 1
stream.map(item ->{item.setAge(item.getAge() + 1); return item;}).forEach(System.out::println);
扁平化,例如将字符数组的字符转换为字母,并将重复字母去掉
List<String> words = Arrays.asList("Hello", "Wrold");
words.stream()
.map(word -> word.split(""))
.flatMap((Arrays::stream)) // 扁平化,把map(Arrays::stream)生成的单个流合并成一个流
.distinct()
.forEach(System.out::println);
去重
// 利用hashcode 跟 equals 作为重复判断依据
stream04.distinct().forEach(System.out::println);
还可以将多个中间操作配合使用,比如加入有业务需要 无重复的列出所有已成年男性,我们就可以这样写
stream
.filter(item -> item.getAge() > 18 && "男".equals(item.getSex())) // 过滤掉未成年及女生
.distinct() // 去重,是利用HashCode与equals方法去重
.forEach(System.out::println); // 终止操作
在上面的示例中 .forEach()
就是终止操作
将Strea生成一个新的集合
// 转换为ArrayList
Stream<Integer> stream01 = Stream.iterate(0, x -> (x + 1));
stream01.limit(10).collect(Collectors.toList())
// 转换为HashSet
Stream<Integer> stream02 = Stream.iterate(0, x -> (x + 1));
stream02.limit(10).collect(Collectors.toSet())
用 Stream 表示全体自然数(其实就是上面迭代的那个例子)
// 全体自然数
Stream<Integer> stream = Stream.iterate(0, x -> (x + 1));
// 取前十个
stream.limit(10).forEach(System.out::println);
利用函数式接口 Supplier
实现
public class Natural implements Supplier<Integer> {
private Integer number = 0;
// 获取自然数
@Override
public Integer get() {
return this.number++;
}
}
@Test
public void test03() {
Stream<Integer> stream = Stream.generate(new Natural());
stream.limit(10).forEach(System.out::println);
}
package stream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Test;
public class StreamDemo {
/*
* 获取Stream的方式
*/
@Test
public void test01() {
// 1. 通过Collections系列集合提供的stream() 或 parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream01 = list.stream();
// 2. 通过Arrays中的静态方法stream()获取数组流
String[] strList = new String[10];
Stream<String> stream02 = Arrays.stream(strList);
// 3. 通过Stream类中的静态方法
Stream<String> stream03 = Stream.of(strList);
// 4. 迭代
Stream<Integer> stream04 = Stream.iterate(0, (x) -> (x + 2));
stream04.limit(10).forEach(System.out::println);
// 5. 生成
Stream<Double> stream05 = Stream.generate(() -> Math.random());
stream05.limit(10).forEach(System.out::println);
}
/*
* 中间API
*/
@Test
public void test02() {
List<Human> list = new ArrayList<>();
list.add(new Human("小王", 31, "男"));
list.add(new Human("小黑", 24, "女"));
list.add(new Human("小张", 10, "男"));
list.add(new Human("胖虎", 15, "男"));
list.add(new Human("小王", 31, "男"));
list.add(new Human("胖虎", 15, "男"));
// 获取流
Stream<Human> stream = list.stream();
// list.get(1).setAge(45);
/*
* 中间操作
*/
// 过滤
Stream<Human> stream01 = list.stream();
System.out.println("============== 过滤 ================");
stream01.filter(item -> item.getAge() > 20).forEach(System.out::println);
// 切片,取下标 [2,4) 的元素
Stream<Human> stream02 = list.stream();
System.out.println("=============== 切片 ===============");
stream02.skip(2).limit(3).forEach(System.out::println);
// 去重
Stream<Human> stream04 = list.stream();
System.out.println("=============== 去重 ===============");
stream04.distinct().forEach(System.out::println);
// 映射,将函数作用于每个元素
Stream<Human> stream05 = list.stream();
System.out.println("=============== 映射 ===============");
stream05.map(item ->{item.setAge(item.getAge() + 1); return item;}).forEach(System.out::println);
// 中间操作返回的还是Stream,所以可以将多个中间操作组合使用
Stream<Human> stream06 = list.stream();
System.out.println("=============== 配合使用 ===============");
stream06
.filter(item -> item.getAge() > 18 && "男".equals(item.getSex())) // 过滤掉未成年及女生
.distinct() // 去重,是利用HashCode与equals方法去重
.forEach(System.out::println); // 终止操作
System.out.println("=============== 查看数据是否被改变 ===============");
for (Human human : list) {
System.out.println(human);
}
}
/**
* 自然数一
*/
@Test
public void test03() {
Stream<Integer> stream = Stream.generate(new Natural());
stream.limit(10).forEach(System.out::println);
}
/**
* 自然数二
*/
@Test
public void test04() {
Stream<Integer> stream = Stream.iterate(0, x -> (x + 1));
stream.limit(10).forEach(System.out::println);
}
@Test
public void test05() {
// 转换为ArrayList
Stream<Integer> stream01 = Stream.iterate(0, x -> (x + 1));
System.out.println(stream01.limit(10).collect(Collectors.toList()).getClass());
// 转换为HashSet
Stream<Integer> stream02 = Stream.iterate(0, x -> (x + 1));
System.out.println(stream02.limit(10).collect(Collectors.toSet()).getClass());
}
/**
* 分组
*/
@Test
public void test06() {
List<Human> list = new ArrayList<>();
list.add(new Human("小王", 31, "男"));
list.add(new Human("小黑", 24, "女"));
list.add(new Human("小张", 10, "男"));
list.add(new Human("胖虎", 15, "女"));
list.add(new Human("小王", 31, "男"));
list.add(new Human("胖虎", 15, "女"));
Stream<Human> stream = list.stream();
Map<String, List<Human>> map = stream.collect(Collectors.groupingBy(Human::getSex));
System.out.println(map.size() + ": " + map.keySet());
System.out.println(map.get("男"));
System.out.println(map.get("女"));
}
}
网友评论