初识Java8中的Stream
lambda表达式是stream的基础,初学者建议先学习lambda表达式,http://www.jb51.net/article/121129.htm 1.初识stream 先来一个总纲: 东西就是这么多啦,stream是java8中加入的一个非常实用的功能,最初看时以为是io中的流(其实一点关系都没有),让我们先来看一个小例子感受一下: @Before public void init() { random = new Random(); stuList = new ArrayList<Student>() { { for (int i = 0; i < 100; i++) { add(new Student("student" + i,random.nextInt(50) + 50)); } } }; } public class Student { private String name; private Integer score; //-----getters and setters----- } //1列出班上超过85分的学生姓名,并按照分数降序输出用户名字 @Test public void test1() { List<String> studentList = stuList.stream() .filter(x->x.getScore()>85) .sorted(Comparator.comparing(Student::getScore).reversed()) .map(Student::getName) .collect(Collectors.toList()); System.out.println(studentList); } 列出班上分数超过85分的学生姓名,并按照分数降序输出用户名字,在java8之前我们需要三个步骤: 1)新建一个List<Student> newList,在for循环中遍历stuList,将分数超过85分的学生装入新的集合中 2)对于新的集合newList进行排序操作 3)遍历打印newList 这三个步骤在java8中只需要两条语句,如果紧紧需要打印,不需要保存新生产list的话实际上只需要一条,是不是非常方便。 2.stream的特性 我们首先列出stream的如下三点特性,在之后我们会对照着详细说明 1.stream不存储数据 2.stream不改变源数据 3.stream的延迟执行特性 通常我们在数组或集合的基础上创建stream,stream不会专门存储数据,对stream的操作也不会影响到创建它的数组和集合,对于stream的聚合、消费或收集操作只能进行一次,再次操作会报错,如下代码: @Test public void test1(){ Stream<String> stream = Stream.generate(()->"user").limit(20); stream.forEach(System.out::println); stream.forEach(System.out::println); } 程序在正常完成一次打印工作后报错。 stream的操作是延迟执行的,在列出班上超过85分的学生姓名例子中,在collect方法执行之前,filter、sorted、map方法还未执行,只有当collect方法执行时才会触发之前转换操作 看如下代码: public boolean filter(Student s) { System.out.println("begin compare"); return s.getScore() > 85; } @Test public void test() { Stream<Student> stream = Stream.of(stuArr).filter(this::filter); System.out.println("split-------------------------------------"); List<Student> studentList = stream.collect(toList()); } 我们将filter中的逻辑抽象成方法,在方法中加入打印逻辑,如果stream的转换操作是延迟执行的,那么split会先打印,否则后打印,代码运行结果为 可见stream的操作是延迟执行的。 TIP: 当我们操作一个流的时候,并不会修改流底层的集合(即使集合是线程安全的),如果想要修改原有的集合,就无法定义流操作的输出。 由于stream的延迟执行特性,在聚合操作执行前修改数据源是允许的。 List<String> wordList; @Before public void init() { wordList = new ArrayList<String>() { { add("a"); add("b"); add("c"); add("d"); add("e"); add("f"); add("g"); } }; } /** * 延迟执行特性,在聚合操作之前都可以添加相应元素 */ @Test public void test() { Stream<String> words = wordList.stream(); wordList.add("END"); long n = words.distinct().count(); System.out.println(n); } 最后打印的结果是8 如下代码是错误的 /** * 延迟执行特性,会产生干扰 * nullPointException */ @Test public void test2(){ Stream<String> words1 = wordList.stream(); words1.forEach(s -> { System.out.println("s->"+s); if (s.length() < 4) { System.out.println("select->"+s); wordList.remove(s); System.out.println(wordList); } }); } 结果报空指针异常 3.创建stream 1)通过数组创建 /** * 通过数组创建流 */ @Test public void testArrayStream(){ //1.通过Arrays.stream //1.1基本类型 int[] arr = new int[]{1,2,34,5}; IntStream intStream = Arrays.stream(arr); //1.2引用类型 Student[] studentArr = new Student[]{new Student("s1",29),new Student("s2",27)}; Stream<Student> studentStream = Arrays.stream(studentArr); //2.通过Stream.of Stream<Integer> stream1 = Stream.of(1,5,65); //注意生成的是int[]的流 Stream<int[]> stream2 = Stream.of(arr,arr); stream2.forEach(System.out::println); } 2)通过集合创建流 /** * 通过集合创建流 */ @Test public void testCollectionStream(){ List<String> strs = Arrays.asList("11212","dfd","2323","dfhgf"); //创建普通流 Stream<String> stream = strs.stream(); //创建并行流 Stream<String> stream1 = strs.parallelStream(); } 3)创建空的流 @Test public void testEmptyStream(){ //创建一个空的stream Stream<Integer> stream = Stream.empty(); } 4)创建无限流 @Test public void testUnlimitStream(){ //创建无限流,通过limit提取指定大小 Stream.generate(()->"number"+new Random().nextInt()).limit(100).forEach(System.out::println); Stream.generate(()->new Student("name",10)).limit(20).forEach(System.out::println); } 5)创建规律的无限流 /** * 产生规律的数据 */ @Test public void testUnlimitStream1(){ Stream.iterate(0,x->x+1).limit(10).forEach(System.out::println); Stream.iterate(0,x->x).limit(10).forEach(System.out::println); //Stream.iterate(0,x->x).limit(10).forEach(System.out::println);与如下代码意思是一样的 Stream.iterate(0,UnaryOperator.identity()).limit(10).forEach(System.out::println); } 4.对stream的操作 1)最常使用 map:转换流,将一种类型的流转换为另外一种流 /** * map把一种类型的流转换为另外一种类型的流 * 将String数组中字母转换为大写 */ @Test public void testMap() { String[] arr = new String[]{"yes","YES","no","NO"}; Arrays.stream(arr).map(x -> x.toLowerCase()).forEach(System.out::println); } (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |