1.概述:
Stream流是JDK8新增的成员,允许以声明性方式处理数据集合,可以把Stream流看作是遍历数据集合的一个高级迭代器。Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找/筛选/过滤、排序、聚合和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
2.使用流的好处
代码以声明性方式书写,说明想要完成什么,而不是说明如何完成一个操作。可以把几个基础操作连接起来,来表达复杂的数据处理的流水线,同时保持代码清晰可读。
1.流是什么
从操作角度来看,流与集合是不同的. 流不存储数据值; 流的目的是处理数据,它是关于算法与计算的。如果把集合作为流的数据源,创建流时不会导致数据流动; 如果流的终止操作需要值时,流会从集合中获取值; 流只使用一次。流中心思想是延迟计算,流直到需要时才计算值。
Stream可以由数组或集合创建,对流的操作分为两种:
中间操作,每次返回一个新的流,可以有多个。
终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。
- 通过集合
List<String> asList = Arrays.asList("11", "22", "33", "44", "55");
asList.stream()
.forEach(System.out::println);
// 输出
//11
//22
//33
//44
//55
- map生成流
Map<String,Integer> myMap=new HashMap<String,Integer>(){
{
put("一号人物",1);
put("二号人物",2);
put("三号人物",3);
put("四号人物",4);
put("五号人物",5);
}
};
myMap.keySet().stream().forEach(s -> System.out.print(s+","));
System.out.println();
myMap.values().forEach(s-> System.out.print(s+","));
System.out.println();
myMap.entrySet().forEach(s-> System.out.print(s+","));
//输出
//二号人物,三号人物,四号人物,一号人物,五号人物,
//2,3,4,1,5,
//二号人物=2,三号人物=3,四号人物=4,一号人物=1,五号人物=5,
2. 数组生成流
Arrays.stream(new int[]{1,5,3,6,8,87})
.forEach(System.out::println);
// 输出
//1
//5
///3
//6
//8
//87
3. 值生成流
// 通过Stream的of方法生成流,通过Stream的empty方法可以生成一个空流.
Stream.of(11,12,15,16,1856,1777,110)
.forEach(System.out::println);
// 输出
//11
//12
//15
//16
//1856
//1777
//110
- 通过文件生成
// 通过Files.line方法得到一个流,并且得到的每个流是给定文件中的一行.
try {
Stream<String> lines = Files.lines(Paths.get("D:\\tmp\\test.txt"), Charset.defaultCharset());
lines.forEach(System.out::println);
} catch (IOException e) {
throw new RuntimeException(e);
}
5. 通过函数生成
// iterate方法接受两个参数,第一个为初始化值,第二个为进行的函数操作,因为iterator生成的流为无限流,通过limit方法对流进行了截断,只生成5个偶数。
Stream<String> iterateStream = Stream.iterate("test", t -> {
int second = LocalDateTime.now().getSecond();
return t + second;
}).limit(3);
iterateStream.forEach(System.out::println);
// 输出
//test
//test50
//test5050
Stream<String> limit = Stream.generate(() -> {
Random random = new Random();
String i = "test-"+random.nextInt(12);
return i;
}).limit(3);
limit.forEach(System.out::println);
// 输出
//test-2
//test-1
//test-10
6. 生成并行流
List<Person> personList = createPersonList();
personList.stream().parallel().forEach(person -> System.out.println("person = " + person));
personList.parallelStream()
.forEach(person -> System.out.println("person = " + person));
3. 中间操作
1. filter 筛选
//Stream<T> filter (Predicate predicate)
// 通过使用filter方法进行条件筛选,filter的方法参数为一个条件(过滤保留函数返回值为 true 的元素)。
List<Person> collect = personList.stream().filter(person -> person.getAge() > 18).collect(Collectors.toList());
2. limit 返回指定流个数
// Stream<T> limit(long maxSize):返回此流中的元素组成的流,截取前指定参数个数的数据
// 通过limit方法指定返回流的个数,limit的参数值必须 >=0,否则将会抛出异常。
List<Person> collect1 = personList.stream()
.limit(3)
.collect(Collectors.toList());
System.out.println("collect1 = " + collect1);
3. skip 跳过流中的元素
// Stream<T> skip(long n):跳过指定参数个数的数据,返回由该流的剩余元素组成的流
List<Person> collect2 = personList.stream().skip(2).collect(Collectors.toList());
System.out.println("collect2 = " + collect2);
//跳过2个元素,把剩下的元素在前两个在控制台输出
personList.stream().skip(2).limit(2).forEach(System.out::println);
4. distinct 去重
// Stream<T> distinct()
// 通过对象的equals方法进行判断,需重写equals方法和hashcode,或者使用lombok的@EqualsAndHashCode
// 通过distinct方法快速去除重复的元素。返回由该流的不同元素(根据Object.equals(Object) )组成的流
personList.stream().distinct().forEach(System.out::println);
System.out.println("personList.stream().distinct().count() = " + personList.stream().distinct().count());
5. sorted排序
// Stream<T> sorted(Comparator comparator):返回由该流的元素组成的流,根据提供的Comparator进行排序
// 基本数据类型的排序比较可以直接sorted
Arrays.asList(1,78,9,12).stream()
.sorted()
.forEach(System.out::println);
// 对象就需要重写Comparator接口
personList.stream().sorted((o1, o2) -> {// 根据age顺序排序,根据salary逆序排序
int result1 = o1.getAge().compareTo(o2.getAge());
if (0 == result1){
return o1.getSalary().compareTo(o2.getSalary())*-1;
}else {
return result1;
}
}).forEach(System.out::println);
6. map流映射
//<R> Stream<R> map(Function mapper):返回由给定函数应用于此流的元素的结果组成的流;
personList.stream().map(new Function<Person, String>() {
@Override
public String apply(Person person) {
return person.getName()+"-"+person.getAge();
}
}).forEach(System.out::println);
// lambda
personList.stream()
.map(person -> person.getName()+"-"+person.getAge())
.forEach(System.out::println);
// 输出
//test01-10
//test02-30
//test03-16
//test04-27
7. flatMap 流转换
// <R> Stream<R> flatMap(Function mapper);
// 将一个流中的每个值都转换为另一个流.
// 找出person的name包含的字符
personList.stream().flatMap(new Function<Person, Stream<?>>() {
@Override
public Stream<?> apply(Person person) {
return Arrays.stream(person.getName().split(""));
}
})
.distinct()
.forEach(c-> System.out.print(c));
// lambda
personList.stream()
.flatMap(person -> Arrays.stream(person.getName().split("")))
.distinct()
.forEach(c-> System.out.print(c));