Stream实例

0.接口简述

Stream 的特性可以归纳为:

  • 不是数据结构
  • 它没有内部存储,它只是用操作管道从 source(数据结构、数组、generator function、IO channel)抓取数据。
  • 它也绝不修改自己所封装的底层数据结构的数据。例如 Stream 的 filter 操作会产生一个不包含被过滤元素的新 Stream,而不是从 source 删除那些元素。
  • 所有 Stream 的操作必须以 lambda 表达式为参数
  • 不支持索引访问
    你可以请求第一个元素,但无法请求第二个,第三个,或最后一个
  • 很容易生成数组或者 List
  • 惰性化
  • 很多 Stream 操作是向后延迟的,一直到它弄清楚了最后需要多少数据才会开始。
  • Intermediate 操作永远是惰性化的。
  • 并行能力
  • 当一个 Stream 是并行化的,就不需要再写多线程代码,所有对它的操作会自动并行进行的。
  • 可以是无限的
  • 集合有固定大小,Stream 则不必。limit(n) 和 findFirst() 这类的 short-circuiting 操作可以对无限的 Stream 进行运算并很快完成。

在对于一个 Stream 进行多次转换操作 (Intermediate 操作),每次都对 Stream 的每个元素进行转换,而且是执行多次,这样时间复杂度就是 N(转换次数)个 for 循环里把所有操作都做掉的总和吗?其实不是这样的,转换操作都是 lazy 的,多个转换操作只会在 Terminal 操作的时候融合起来,一次循环完成。我们可以这样简单的理解,Stream 里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,在 Terminal 操作的时候循环 Stream 对应的集合,然后对每个元素执行所有的函数。
常见的操作可以归类如下:
Intermediate
一个流后面可以跟随零个或者多个Intermediate操作,其主要目的是打开流,做出某种程度的数据映射或者过滤,然后返回一个新的流,交给下一个操作使用,这类操作都是惰性化的,也就是说调用这类方法并没有真正开始流的遍历

  • map (mapToInt, flatMap 等)、
  • filter(filter 对原始 Stream 进行某项测试,通过测试的元素被留下来生成一个新 Stream。)、
  • distinct(依靠对象的toString()和hashCode()方法,对自定义类的对象去重一定要重写其中一个方法)、
  • sorted(默认是升序排列)、
  • peek(peek 对每个元素执行操作并返回一个新的 Stream)、
  • parallel、
  • sequential、
  • unordered

Terminal
一个流只能有一个terminal操作,当这个操作执行之后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作,terminal操作的执行才会真正开始流的遍历,并且会生成一个结果或者一个side effect。

  • forEach(forEach 方法接收一个 Lambda 表达式,然后在 Stream 的每一个元素上执行该表达式)、
  • forEachOrdered、
  • toArray、
  • reduce、
  • collect、
  • min、
  • max、
  • count、
  • anyMatch(Stream 中只要有一个元素符合传入的 predicate,返回 true)、
  • allMatch(Stream 中全部元素符合传入的 predicate,返回 true)、
  • noneMatch(Stream 中没有一个元素符合传入的 predicate,返回 true)、
  • findFirst(这是一个 termimal 兼 short-circuiting 操作,它总是返回 Stream 的第一个元素)、
  • findAny、
  • iterator

Short-circuiting:

  • anyMatch、
  • allMatch、
  • noneMatch、
  • findFirst、
  • findAny、
  • limit(limit 返回 Stream 的前面 n 个元素)
  • skip(skip 跳过前 n 个元素)
    注意
  • limit与skip操作和sorted操作的使用次序、影响及性能、
  • sorted之后 再执行limit与skip,无影响
1.创建Stream
public void buildStream() {

        //1.Stream.of() 创建
        Stream stream = Stream.of("a", "b", "c");
        stream.forEach(System.out::println);

        //2.基本类型对应的Stream创建,int -> IntStream , double -> DoubleStream
        IntStream.of(new int[]{1, 2, 3, 4}).forEach(System.out::println);
        IntStream.range(1, 4).forEach(System.out::println);
        
        //3.最常用的用集合直接创建
        List<String> list = Lists.newArrayList("a", "b", "c", "c");
        list.stream();

    }
   output:
a
b
c
1
2
3
4
1
2
3

简单看一下Stream的类结构:

public interface Stream<T> extends BaseStream<T, Stream<T>> {...}
public interface IntStream extends BaseStream<Integer, IntStream> {...}

/** 
 * @param <T> the type of the stream elements
 * @param <S> the type of of the stream implementing {@code BaseStream}
 * @since 1.8
 * @see Stream
 * @see IntStream
 * @see LongStream
 * @see DoubleStream
 * @see <a href="package-summary.html">java.util.stream</a>
 */
public interface BaseStream<T, S extends BaseStream<T, S>> extends AutoCloseable {...}
2.流和集合(list、map、stack…)的转换
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    /**
     * 辅助类
     */
    private Long id;
    private String name;
    private Double grade;
}

public void transfrom() {
        List<String> list = Lists.newArrayList("a", "b", "c", "c");
        List<String> list1 = list.stream()
                .collect(Collectors.toList());
        System.out.println("list1:" + list1);

        List<String> list2 = list.stream()
                .collect(Collectors.toCollection(ArrayList::new));
        System.out.println("list2:" + list2);

        Set<String> set = list.stream()
                .collect(Collectors.toSet());
        System.out.println("set:" + set);

        Stack<String> stack = list.stream()
                .collect(Collectors.toCollection(Stack::new));
        System.out.println("stack:" + stack);

        String str = list.stream()
                .collect(Collectors.joining()).toString();
        System.out.println("str:" + str);


        List<Student> students = Lists.newArrayList();
        Student student1 = new Student(102L, "java", 93D);
        Student student2 = new Student(103L, "python", 98.5);
        Student student3 = new Student(101L, "go", 90D);
        students.add(student1);
        students.add(student2);
        students.add(student3);
        Map<Long, String> map = students.stream()
                .collect(Collectors.toMap(Student::getId, Student::getName));
        map.forEach((key, value) -> {
            System.out.print(key + ":" + value + ", ");
        });
    }
    
output:
	list1:[a, b, c, c]
	list2:[a, b, c, c]
	set:[a, b, c]
	stack:[a, b, c, c]
	str:abcc
	101:go, 102:java, 103:python, 
3.map、flatMap接口实例演示
public void mapTest() {
        List<String> list = Lists.newArrayList("map", "flatMap", "stream");

        List<String> list1 = list.stream()
                .map(x -> {
                    String s = x.toUpperCase();
                    return s;
                })
                .collect(Collectors.toList());
        System.out.println("list1:" + list1);

        List<String> list2 = list.stream()
                .map(String::toUpperCase)
                .collect(Collectors.toList());
        System.out.println("list2:" + list2);


        List<String> list3 = list.stream()
                .map(x -> x.toUpperCase())
                .collect(Collectors.toList());
        System.out.println("list3:" + list3);

        //多个list拍平铺开,放进一个list中
        Stream<List<Integer>> inputStream = Stream.of(
                Arrays.asList(1),
                Arrays.asList(2, 3),
                Arrays.asList(4, 5, 6)
        );
        Stream<Integer> outputStream = inputStream.
                flatMap((childList) -> childList.stream());

        outputStream.forEach(System.out::println);
        //123456
    }

output:
	list1:[MAP, FLATMAP, STREAM]
	list2:[MAP, FLATMAP, STREAM]
	list3:[MAP, FLATMAP, STREAM]
	1
	2
	3
	4
	5
	6

注意:

          List<String> list1 = list.stream().map(x -> {
                     x.toUpperCase();
                     return x;
                 }).collect(Collectors.toList());

不生效,因为流的属性以及map方法决定了其元素不会改变

将小写转换为大写的两种方式

  1. 双冒号:: -> 仅适用于会返回同种类型的方法,
    或者说下例中Stream元素是String类型,toUpperCase()返回String,可以使用,contains()就不可以这么用
  2. lambda表达式,像例子中所展示的比较好理解
4.filter
public void filterTest() {
        List<String> list = Lists.newArrayList("map", 
        "     "/*五个空格*/, "flatMap", "filter", "java", "mybatis");
        list.stream()
                .filter(x -> x.length() > 4)
                .forEach(System.out::println);
    }
    //挑选出长度大于4的
output:
      (这是一个空行)
flatMap
filter
mybatis
5.findfirst
public void findFirst() {
        List<String> list = Lists.newArrayList("c/c++", "java", "python", "java", "golong", "java");
        Optional<String> first = list.stream()
                .findFirst();

        if (first.isPresent()) {
            System.out.println("list first :" + first.get());
        } else {
            System.out.println("list no element!");
        }

        List<String> list1 = Lists.newArrayList();
        Optional<String> first1 = list1.stream()
                .findFirst();


        if (first1.isPresent()) {
            System.out.println("list1 first :" + first1.get());
        } else {
            System.out.println("list1 no element!");
        }

    }
output:
list first :c/c++
list1 no element!
6.sorted
public void sortedTest() {
        List<String> list = Lists.newArrayList("c/c++", "java", "python", "java", "golong", "java");
        list.stream()
                .sorted()
                .forEach(System.out::println);
        //默认排序方式是升序!

        List<Student> students = Lists.newArrayList();
        Student student1 = new Student(102L, "java", 93D);
        Student student2 = new Student(103L, "python", 98.5);
        Student student3 = new Student(101L, "go", 90D);
        students.add(student1);
        students.add(student2);
        students.add(student3);
//        System.out.println("students:" + students);
//
//        List<Student> collect = students.stream()
//                .sorted()
//                .collect(Collectors.toList());
//        //报错 java.lang.ClassCastException
//        System.out.println("after sorted by defult:" + collect);

        List<Student> collect1 = students.stream()
                .sorted(Comparator.comparing(Student::getGrade).reversed())
                .collect(Collectors.toList());

        System.out.println("after sorted by grade:" + collect1);

        List<Student> collect2 = students.stream()
                .sorted((x1, x2) -> x1.getId().compareTo(x2.getId()))
                .collect(Collectors.toList());

        System.out.println("after sorted by id:" + collect2);
    }

output:
c/c++
golong
java
java
java
python
after sorted by grade:[Student(id=103, name=python, grade=98.5), Student(id=102, name=java, grade=93.0), Student(id=101, name=go, grade=90.0)]
after sorted by id:[Student(id=101, name=go, grade=90.0), Student(id=102, name=java, grade=93.0), Student(id=103, name=python, grade=98.5)] 
7.distinct
public void distinctTest() {
        List<Student> students = Lists.newArrayList();
        Student student1 = new Student(102L, "java", 93D);
        Student student2 = new Student(103L, "python", 98.5);
        Student student3 = new Student(101L, "go", 90D);
        Student student4 = new Student(103L, "python", 98.5);
        Student student5 = new Student(101L, "go", 90D);
        students.add(student1);
        students.add(student2);
        students.add(student3);
        students.add(student4);
        students.add(student5);
        System.out.println("students:" + students);

        List<Student> studentsList = students.stream()
                .distinct()
                .collect(Collectors.toList());
        System.out.println("after distinct:" + studentsList);
    }
output:
students:[Student(id=102, name=java, grade=93.0), Student(id=103, name=python, grade=98.5), Student(id=101, name=go, grade=90.0), Student(id=103, name=python, grade=98.5), Student(id=101, name=go, grade=90.0)]
after distinct:[Student(id=102, name=java, grade=93.0), Student(id=103, name=python, grade=98.5), Student(id=101, name=go, grade=90.0)]

注意:

  • 去重方法依据的是对象的toString()和hashCode()方法,来判定对象是否相等
  • 本例中Student未实现这两个方法,但还是能够去重,这是因为继承自Object类自动实现的,并且成功的起到了判定依据,从上面的代码中可以看出, System.out.println(“students:” + students);的结果就是调用了自动实现的toString()方法,实际中不一定会生效,需要自己手动实现这两个方法
8.匹配
public void matchTest() {
        List<String> list = Lists.newArrayList("c/c++", "javaee", "python", "javase", "golong", "javaleran");
        System.out.println("list:" + list);

        boolean isHasJava = list.stream()
                .anyMatch(x -> x.contains("java"));
        System.out.println("is Has Java ? :" + isHasJava);

        boolean isAllLength = list.stream()
                .allMatch(x -> x.length() > 4);
        System.out.println("is All Length than 4 ? :" + isAllLength);

        boolean isNoneReact = list.stream()
                .noneMatch(x -> x.equals("react") || x.contains("react"));
        System.out.println("is None React ? :" + isNoneReact);

    }
output:
list:[c/c++, javaee, python, javase, golong, javaleran]
is Has Java ? :true
is All Length than 4 ? :true
is None React ? :true
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值