package stream;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class StreamDemo {
public static void main(String[] args) {
System.out.println("-------------Stream对象的构建----------------");
/**
* 1. Stream对象的构建
*/
// 1. Stream的构建
// 看底层源码, Stream.of 用的是 Arrays.stream(values); 来构建,因此可以用Arrays进行构建
Stream stream01 = Stream.of("a", "b", "c");
// 2. Arrays 用数组构建
String[] strArr = new String[]{"a", "b", "c"};
Stream stream03 = Stream.of(strArr);
Stream stream02 = Arrays.stream(strArr);
// 3. 利用集合进行构建, 先创建一个集合,在从集合转换成Stream
// Arrays.asList 就是把数据变成集合
List list = Arrays.asList(strArr);
Stream stream04 = list.stream();
/**
* 对于基本数值类型,有以下几种Stream流:Stream, IntStream, LongStream, DoubleStream
* 当然我们也可以用Stream Stream Stream
* 但是自动装箱拆箱会很耗时,所以特别为这三种Stream提供了特定的Stream
* Java8 中还没提供其他数据类型的Stream
*/
System.out.println("-------------Stream的基本类型对象的构建----------------");
/**
* 2. 数值Stream的创建
*/
// 1. 使用IntStream.of
IntStream intStream = IntStream.of(new int[]{1, 2, 3});
// 2. 使用数组创建
IntStream intStream1 = Arrays.stream(new int[]{1, 2, 3});
// 3. 使用rang方法创建, [1, 3)
IntStream intStream2 = IntStream.range(1, 3);
// 4. 使用rangClose 创建 [1, 3]
IntStream intStream3 = IntStream.rangeClosed(1, 3);
System.out.println("-------------Stream对象转其他类型----------------");
/**
* 3. Stream 转其他类型
*/
Stream stream = Stream.of(new Integer[]{1, 2, 3});
// 1. stream 转数组
Integer[] intArr = stream.toArray(Integer[]::new);
// 2. stream 转集合
List list1 = stream.collect(Collectors.toList());
List list2 = stream.collect(Collectors.toCollection(ArrayList::new));
Set set = stream.collect(Collectors.toSet());
Set set1 = stream.collect(Collectors.toCollection(HashSet::new));
// 3. stream 转为joining
Stream stream1 = Stream.of(new String[]{"1", "b", "c"});
String str1 = stream1.collect(Collectors.joining()).toString();
/**
* 注意:一个Stream只可以被抛出一次,而上面的代码为了简洁重复了多次
* 上面的代码直接运行会抛出异常:java.lang.IllegalStateException 违反规定异常
*/
/**
* Stream操作:当把数据接口包装成stream后,就可以对stream进行各种操作了
*
* Intermediate: 中间操作
* map(mapToInt, faltMap), filter, distinct(去除重复列), sorted(排序), peek, limit, skip, parallel, sequential, unordered
* Short-circuiting: 短路操作
* anyMatch, allMatch, noneMatch, findFirst, findAny, limit
*
*/
// map, flatMap映射:把stream的元素映射成另一个元素。
/**
* 1. 将字符串数组中所有的字符 转成大写
*/
String[] str2 = new String[]{"abc", "hello", "keep", "Time"};
Stream stream2 = Stream.of(str2);
// map是映射操作,collect是对这些数据进行收集,并且返回相应的集合
List list3 = stream2.
map(String::toUpperCase).
collect(Collectors.toList());
System.out.println(list3.toString());
/**
* Stream操作:当把数据接口包装成stream后,就可以对stream进行各种操作了
*
* Intermediate: 中间操作
* map(mapToInt, faltMap), filter, distinct(去除重复列), sorted(排序), peek, limit, skip, parallel, sequential, unordered
* Short-circuiting: 短路操作
* anyMatch, allMatch, noneMatch, findFirst, findAny, limit
*
*/
// map, flatMap映射:把stream的元素映射成另一个元素。
/**
* 1. 将字符串数组中所有的字符 转成大写
*/
String[] str2 = new String[]{"abc", "hello", "keep", "Time"};
Stream stream2 = Stream.of(str2);
// map是映射操作,collect是对这些数据进行收集,并且返回相应的集合
List list3 = stream2.
map(String::toUpperCase).
collect(Collectors.toList());
System.out.println(list3.toString());
System.out.println("-------for-Each循环-------");
// 对于stream流,可以对其进行forEach循环操作
// 此处我犯了一个错误,一个Stream流只能用一次,因此要重新创建一个stream流
Stream stream = Stream.of(str2);
stream.
map(s -> s.toUpperCase()).
collect(Collectors.toList()).
forEach(s -> System.out.println(s));
// 如果对stream进行操作一般不会创建一个stream对象,而是使用List.stream(); 集合
// 2. 对Integer的集合进行平方操作
Integer[] init = new Integer[]{1, 2, 3, 4, 5};
List list = Arrays.asList(init);
list.stream().
map(i -> i * i).
forEach(i -> System.out.println(i));
System.out.println("--------------flatMap的用法----------------");
/**
* 3. map生成的是1:1关系,而flatMap 对应的是1:N 关系
* map: Stream map(Function super T, ? extends R> mapper);
* flatMap: Stream flatMap(Function super T, ? extends Stream extends R>> mapper);
*/
Stream> stream1 = Stream.of(Arrays.asList(1), Arrays.asList(2, 3), Arrays.asList(4, 5, 6));
Stream stream3 = stream1.flatMap(e -> e.stream());
stream3.forEach(i -> System.out.println(i + 1));
/**
* forEach 方法:带入参数,然后不返回任何参数。
*/
System.out.println("------测试flatMap----------");
// 将字符串 tom.Li lucy.Liu 用'.' 作为分割,返回4个字符串
Stream stream4 = Stream.of("tom.Li", "lucy.Liu");
Stream stream5 = stream4.flatMap(e -> Stream.of(e.split("[.]")));
stream5.forEach(System.out::println);
/**
* filter: 对Stream进行筛选,筛选下来的元素生成一个新的Stream
* 通过一个predicate接口来过滤并只保留符合条件的元素,该操作属于中间操作,
* 所以我们可以在过滤后的结果来应用其他Stream操作(比如forEach, 比如collect操作)。
* forEach需要一个函数来对过滤后的元素依次执行。
* forEach是一个最终操作,所以我们不能在forEach之后来执行其他Stream操作
*/
System.out.println("---------filter方法的使用-------------------");
List list1 = Arrays.asList("Hi", "Hello", "Sea", "Sun", "TomAndSally");
Stream stream6 = list1.stream().filter(s -> s.length() > 3);
// 这里我筛选出字符串长度 > 3 的数据,返回一个集合
List list2 = list1.stream().filter(s -> s.length() > 3).collect(Collectors.toList());
System.out.println("List2 = " + list2.toString());
stream6.forEach(System.out::println);
System.out.println("-------------peek的用法---------------");
/**
* 发现了一个规律,peek和filter的筛选不是
*/
List list4 = list1.stream().
filter(e -> e.length() > 2).
peek(s -> System.out.println("长度大于2 的字符串为:" + s)).
filter(e -> e.length() > 3).
peek(s -> System.out.println("长度大于3的字符串为:" + s)).
collect(Collectors.toList());
System.out.println("peek的用法: " + list4.toString());
/**
* findFirst: 返回stream流中的第一个元素,返回值类型Optional
*/
System.out.println("---------findFirst的用法-----------------");
List list5 = Arrays.asList("ab", "cde");
Optional first = list5.stream().findFirst();
System.out.println(first.orElse("该集合为空"));
/**
* sort排序:排序是一个中间操作,返回的是排序好后的stream操作。如果你不能制定一个自定义的排序,那么就会使用默认排序
* 它比数组的排序更强的作用是,你在排序前对Stream进行 map, flatMap, filter, limit, distinct, skip来减少元素数量
* 筛选后进行排序能够大大的缩短执行时间
*/
System.out.println("---------sorted排序----------------");
List list6 = Arrays.asList("test", "hello", "world", "java", "tom", "C", "javascript");
// 1. 按照默认进行排序
// 默认排序是按照首字母大小从小往大排序
Stream stream7 = list6.stream().sorted();
stream7.forEach(System.out::println);
// 2. 按照字符串长度进行排序
// sorted调用的是compare函数,compare返回一个int类型的值
// 如果长度相同,就按照集合中原先的顺序来
System.out.println("--------------------------");
list6.stream().sorted((s1, s2) -> s1.length() - s2.length()).forEach(System.out::println);
// 3. 先筛选出字符串中有t的,然后按照长度大小排序
System.out.println("-----sorted3---------------");
list6.stream().filter(s -> s.startsWith("t")).sorted((s1, s2) -> s1.length() - s2.length()).forEach(System.out::println);
/**
* Match 匹配:match 提供了多种匹配操作, allMatch 所有的元素都通过, anyMatch 只要有一个通过, noneMatch 一个都不通过
* 所有的匹配都是最终操作,并且返回一个Boolean类型的值。
*/
System.out.println("----------Match匹配--------------");
// 如果list的集合所有的string字符串都有t, 那么返回true
boolean isAllmatch = list6.stream().allMatch(s -> s.startsWith("t"));
System.out.println("isAllmatch = " + isAllmatch);
// 2. anyMatch:只要有一个数据成立,就返回true
boolean anyMatch = list6.stream().anyMatch(s -> s.length() > 5);
System.out.println("anyMatch = " + anyMatch);
// 3. noneMatch: 全都不成立,就返回true
boolean noneMatch = list6.stream().noneMatch(s -> s.isEmpty());
System.out.println("noneMatch = " + noneMatch);
/**
* count:计数是一个最终操作,返回Stream中元素的个数。返回值类型是long
*/
// 返回list6集合中,字符串长度大于3的字符串个数
System.out.println("----------count------------");
long count = list6.stream().filter(s -> s.length() > 3).count();
System.out.println(count);
/**
* 规约合并reduce
* 这是一个最终操作,允许通过制定的函数来将stream中的多个元素规约合并成一个元素
* 它提供了一个起始值,然后按照运算规则,和前面的Stream的第一个,第二个,第n个元素组合
* 常用的方法有average,sum,min,max,and,count,返回单个的结果值
* 并且reduce操作每处理一个元素总是创建一个新值
*/
System.out.println("-----------------reduce----------------");
// 比如stream的sum就相当于
// [1, 10)
IntStream intStream = IntStream.range(1, 10);
IntStream intStream1 = IntStream.range(1, 10);
// 转换成,
Integer sum1 = intStream.reduce(5, (a, b) -> (a + b));
// 或者
Integer sum2 = intStream1.reduce(1, Integer::sum);
// 起始值:start + a + b
System.out.println("返回结果为起始值为5sum1 = " + sum1 + ";或者起始值1sum2 = " + sum2);
// 也有没有起始值的情况,这时候会把stream的前面两个元素组合起来,返回的是optional, 比如min, max
IntStream intStream2 = IntStream.range(1, 10);
OptionalInt optionalInt = intStream2.reduce((a, b) -> a < b ? a : b);
// max
IntStream intStream3 = IntStream.range(1, 10);
OptionalInt optionalInt1 = intStream3.reduce((a, b) -> a > b ? a : b);
// 对于reduce来说,有起始值会返回相应的对应类型,如果没有起始值,会返回一个Optional 的类型
// 比如:contact字符串连接
String str = Stream.of("a", "b", "c", "d").reduce("", String::concat);
System.out.println(str);
Optional optionalS = Stream.of("a", "b", "c", "d").reduce(String::concat);
// 写一个reduce的模板
Optional optionalS1 = list6.stream().
sorted((s1, s2) -> s1.length() - s2.length()).
filter(s -> s.startsWith("t")).
map(s -> s + "perper").
reduce((s1, s2) -> s1 + " | " + s2);
/**
* 1. 先创建一个steam流对象
* 2. 然后将流对象中筛选出首字母为 t 的
* 3. 将筛选出来的stream,每个数据在字母最后加上 + "perper"
* 4. 将所有的数据,用 | 规约合并起来
*/
System.out.println(optionalS1.get());
/**
* limit, skip
* limit:得到前n个元素
* skip:跳过前n个元素
*/
List list7 = Arrays.asList("test","javap","hello","world","java","tom","C","javascript");
// limit 选择前五个元素 "test","javap","hello","world","java"
Stream stream8 = list7.stream().limit(5);
// skip 跳过前五个元素 "tom","C","javascript"
Stream stream9 = list7.stream().skip(5);
/**
* Collector 收集元素, 辅助进行各类有用的操作
* 例如把stream转变为Collection, 或者把Stream 元素进行分组
*/
List list8 = Arrays.asList("test","hello","world","java","tom","C","javascript");
List result = list8.stream().filter(s -> s.startsWith("t")).collect(Collectors.toList());
System.out.println("------按照字符串长度进行分组------------");
// 按照字符串的长度进行分组
Map> collect = list8.stream().collect(Collectors.groupingBy(s -> s.length()));
System.out.println(collect.toString());
/**
* 并行和串行stream
*/
// 生成100万个不同的字符串放到集合中去
int max = 1000000;
List values = new ArrayList(max);
for (int i = 0; i < max; i++) {
UUID uuid = UUID.randomUUID();
values.add(uuid.toString());
}
System.out.println("-----查看并行时间------------");
// 1纳秒 * 10^9 = 1秒
long t0 = System.nanoTime();
// 串行stream 串行时间:832311645
//long count1 = values.stream().sorted().count();
// 并行stream 并行时间:474983692 时间减少了近2倍
long count2 = values.parallelStream().sorted().count();
// 结束时间:t1
long t1 = System.nanoTime();
long time = t1 - t0;
System.out.println(count2);
System.out.println(time);
}
}