Java 8 Stream

754 阅读4分钟

简介

Stream称之为

流的构成

  1. 源(各种集合)
  2. 零个或多个中间操作(对集合中元素的修改和操作)
  3. 终止操作(输出、求和。。。)

创建流

image.png

public class StreamTest1 {
    public static void main(String[] args) {
        int[] a = new int[]{2,4,6,8,7,9,13,16,17};
        Integer[] b = new Integer[]{2,4,6,8,7,9,13,16,17};
        Stream stream = Stream.of(a);
        Stream stream1 = Stream.of("asdf","Asdfsa","sadgggg");
        Stream stream2 = Arrays.stream(b);//基本数据类型数组不行,得是对象数组,如,String 、Integer。。。。
        List<Integer> list = Arrays.asList(b);
        Stream stream3 = list.stream();
    }
}

稍微特殊的流

  • IntStream
public class StreamTest2 {
    public static void main(String[] args) {
        IntStream.range(6,13).forEach( s -> System.out.print(s+" "));//左开右闭区间
    }
}

image.png

继续体验流

将集合中的每个元素乘2并求和

public class StreamTest3 {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2,3,4,5);
        System.out.println(list.stream().map(i -> i * 2).reduce(0, (i, s) -> s = s + i));
    }
}

image.png

  • 代码释义 image.png

如果reduce第一个参数是6,那么s的初始值就是6,最后结果就是36

再者

image.png

再继续体验

  • 将流中的数据,变成数组,并打印
  • 可以使用Stream中的toArray方法 image.png
public class StreamTest4 {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("AABB","CCDD","EEFF","GGHH");
       // System.out.println(stream.count());//求stream中元素个数
        String[] stringArray = stream.toArray(length -> new String[length]);
        //调用toArray时,length会自动求出来
        Arrays.asList(stringArray).forEach(System.out::println);
        //将数组转换成集合。并用forEach,再引用方法,实现forEach参数Consumer
    }
}

Stream.of("AABB","CCDD","EEFF","GGHH"); 不能认为丢进去的元素就已经是数组了,of(T...)的参数是可变长参数,只是表示丢进去多个参数而已,是不是数组得另说

  • 或者使用方法引用
public class StreamTest4 {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("AABB","CCDD","EEFF","GGHH");
        String[] stringArray = stream.toArray(String[]::new);//引用构造方法
        Arrays.asList(stringArray).forEach(System.out::println);
    }
}

使用stream.collect( . . .)

继续

将流中的数据变成List

  • 先上一个耳熟能详的Collectors.toList()
public class StreamTest5 {
    public static void main(String[] args) {
        Stream<Integer> stream = Stream.of(11,22,33,44,55,66);
        List<Integer> list = stream.collect(Collectors.toList());
        list.forEach(l -> System.out.print(l+"  "));
    }
}
  • 再来一个看不懂的
public class StreamTest5 {
    public static void main(String[] args) {
        Stream<Integer> stream = Stream.of(11,22,33,44,55,66);
 
       List<Integer> list2 = stream.collect( () -> new ArrayList<Integer>(),
       (resList,item) -> resList.add(item),
       (resList1,resList) -> resList1.addAll(resList));// stream.collect接收3个参数,看仔细了
        list2.forEach(l -> System.out.print(l+"  "));//打印
    }
}
  • 上面的代码可以使用方法引用
List<Integer> list2 = stream.collect(ArrayList::new, ArrayList::add,
                ArrayList::addAll);

image.png

  • 看看代码

image.png

再者

  • 你可能会认为Collectors.toList()已经够了

image.png

  • 说明:Collectors.toList()只返回ArrayList,如果需要LinkedList或其他,还得手写stream.collect的三个参数(提供商,累加器,组合器)的实现

稍微使用一下神器Collectors

  • stream.collect(Collectors.toList()),这个就不说了
  • Collectors.toCollection(集合的实现类::new)//获得你想要的集合
public class CollectsTest {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("AABB","CCDD","EEFF","GGHH");
                                                                  //将stream转成ArrayList
        List<String> stringList = stream.collect(Collectors.toCollection(ArrayList::new));
        System.out.println(stringList.getClass());
    }
}

image.png

  • 同理

public class CollectsTest {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("AABB","CCDD","EEFF","GGHH");
                                                           //将stream转成TreeSet
        Set<String> stringSet = stream.collect(Collectors.toCollection(TreeSet::new));
        System.out.println(stringSet.getClass());
    }
}

image.png

  • 关于Collectors.toCollection(集合的实现类::new)的实现还是喜闻乐见的三人帮(提供商,累加器,组合器)

image.png

  • 拼接,以指定的分隔符拼接不同元素形成String
public class CollectsTest {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("AABB","CCDD","EEFF","GGHH");
        String str = stream.collect(Collectors.joining("00")); //以00为分隔符拼接成String
        System.out.println(str);
        // Collectors.joining返回值是String
    }
}

image.png

  • 将集合中的String元素变成大写
public class StreamTest6 {
    public static void main(String[] args) {
        List<String> stringList = Arrays.asList("aabb","ccdd","eeff","gghh");
        stringList.stream().map(String::toUpperCase).forEach(System.out::println);
    }
}

image.png

操作List里面的List中的元素,并将多个List的元素放到一个List中

  • 你可能会想当然

image.png

  • 正确解法
public class FlatMap {
    public static void main(String[] args) {
        Stream<List<Integer>> listStream = Stream.of(Arrays.asList(2,4,7),Arrays.asList(8,8),Arrays.asList(13,19));
                                        //扁平化映射
       List<Integer> list = listStream.flatMap(ls -> ls.stream()).map(item ->item*item).collect(Collectors.toList());
        list.forEach(System.out::println);
    }
}

image.png

再来几个应用

Optional相关

  • 体验一下无限流generate()
public class StreamTest7 {
    public static void main(String[] args) {
        Stream<String> stream = Stream.generate(UUID.randomUUID()::toString);//一个新的无限顺序无序Stream
        stream.forEach(System.out::println);//输出不会结束
    }
}
  • 使用findFirst(),返回Optional并将第一个元素封装进去
public class StreamTest7 {
    public static void main(String[] args) {
        Stream<String> stream = Stream.generate(UUID.randomUUID()::toString);//一个新的无限顺序无序Stream
        stream.findFirst().ifPresent(System.out::println);
        //一定要先判断返回的是不是空的Optional,再进行其他操作,防止空指针异常
    }
}

另外一种无限流

  • iterate(final T seed, final UnaryOperator<T> f)
public class StreamTest7 {
    public static void main(String[] args) { 
                     //种子0,就是i的初始值 return i=(i+1)%2
        Stream.iterate(0 ,i -> (i+1)%2).forEach(System.out::println);//无限输出0和1
    }
}
  • 中断无限流
  • 有瑕疵的操作,即输出没有无限,但流没有中断
public class StreamTest7 {
    public static void main(String[] args) {
                                      //去除重复元素,//提取前面6个
        Stream.iterate(0 ,i -> (i+1)%2).distinct().limit(6).forEach(System.out::println);
        //只输出  0和1    ,但程序不会结束 
    }
}

image.png

  • 正常结束它
public class StreamTest7 {
    public static void main(String[] args) {
        Stream.iterate(0 ,i -> (i+1)%2).limit(6).distinct().forEach(System.out::println);
    }
}

先截取固定个数的元素后去除重复才正常。因为流是无限的,先去重的话工作是不会结束的,所以要先截取,流就变成了固定长度,程序就可以结束了