- 流:Stream由三部分构成:
1)源
2)零个或多个中间操作--惰性求值
3)终止操作--及早求值 - 流的说明
1 Collection提供了新的stream()方法
2 流不存储值,通过管道的方式获取值
3 本质是函数式的,对流的操作会生成一个结果,不过并不会修改底层的数据源,集合可以作为流的底层数据源
4 延迟查找,很多流操作(过滤,映射,排序等)都可以延迟实现@Test public void TestStream(){ // 创建流的几种方式 Stream stream1 = Stream.of("we","we","wr","zhang"); String[] arr = new String[]{"Hello","Hi","Good","Bad"}; Stream stream2 = Arrays.stream(arr); Stream stream3 = Stream.of(arr); List<String> list = Arrays.asList("we","we","wr","zhang"); Stream stream4 = list.stream(); } @Test public void UseStream(){ IntStream.of(new int[]{5,6,7}).forEach(System.out::println);// 5 6 7 System.out.println("--------------"); IntStream.range(3, 5).forEach(System.out::println);//3 4 System.out.println("--------------"); IntStream.rangeClosed(3, 5).forEach(System.out::println);//3 4 5 } @Test public void OperatorStream(){ // 实现:整型集合中所有元素相加再乘2得到结果 List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9); System.out.println(list.stream().reduce(Integer::sum).map(i->i*2)); System.out.println(list.stream().map(i->i*2).reduce(0,Integer::sum)); }
- Stream的应用:
@Test public void UseStream2() { //将流转化为数组对象 Stream<String> stream1 = Stream.of("we", "we", "wr", "zhang"); // String[] strings = (String[])stream1.toArray();//方式一 // String[] strings = stream1.toArray(length->new String[length]);//方式二 String[] strings = stream1.toArray(String[]::new);//方式三 Arrays.asList(strings).forEach(System.out::println); } @Test public void UseStream3() { // 将流转化为不同的集合 Stream<String> stream1 = Stream.of("we", "we", "wr", "zhang"); Stream<String> stream2 = Stream.of("we", "we", "wr", "zhang"); Stream<String> stream3 = Stream.of("we", "we", "wr", "zhang"); List<String> list = stream1.collect(Collectors.toList());//方式一 List<String> list2 = stream2.collect(()->new ArrayList<String>(), (list1,item1)->list1.add(item1),(l1,l2)->l1.containsAll(l2));//方式二 List<String> list3 = stream3.collect(LinkedList::new,LinkedList::add,LinkedList::addAll);//方式三 list.forEach(System.out::println); //输出:we we wr zhang list2.forEach(System.out::println);//输出:we we wr zhang list3.forEach(System.out::println);//输出:we we wr zhang } @Test public void UseStream4() { // 将流转化为不同的集合,对流元素进行操作 Stream<String> stream1 = Stream.of("we", "we", "wr", "zhang"); Stream<String> stream2 = Stream.of("we", "we", "wr", "zhang"); Stream<String> stream3 = Stream.of("we", "we", "wr", "zhang"); Set<String> set = stream1.collect(Collectors.toCollection(TreeSet::new));//Set set.forEach(System.out::println);//输出:we wr zhang String str = stream2.collect(Collectors.joining());//连接元素为一个字符串操作 System.out.println(str);//输出:wewrzhang //LinkedList并进行操作: List<String> list = stream3.collect(Collectors.toCollection(LinkedList::new)); list.stream().map(String::toUpperCase).collect(Collectors.toList()). forEach(System.out::println);//输出:WE WR ZHANG //flatMap的使用:得到 将流的每个元素按指定的函数操作后的所有元素形成的流 Stream<List<Integer>> stream = Stream.of(Arrays.asList(1,2), Arrays.asList(1),Arrays.asList(8,9,10)); stream.flatMap(list1 -> list1.stream()).map(i->i*i).forEach(System.out::println); }
进阶:
@Test public void Test(){ Stream<String> stream = Stream.generate(UUID.randomUUID()::toString); stream.findFirst().ifPresent(System.out::println); //findFirst返回流的第一个元素,且类型为Optional Stream.iterate(1, i->i+2).limit(5).forEach(System.out::println); //输出:1 3 5 7 9 System.out.println("------------------------"); //找出其中大于2的元素,然后将每个元素乘以2,然后忽略掉元素中的前两个元素, // 再取流中的前两个元素,再求总和/最小值 Stream<Integer> stream1 = Stream.iterate(1, i->i+2).limit(5); Stream<Integer> stream2 = Stream.iterate(1, i->i+2).limit(5); Stream<Integer> stream3 = Stream.iterate(1, i->i+2).limit(5); // stream1.filter(i->i>2).map(i->i*2).skip(2).limit(2).reduce(Integer::sum); // System.out.println(stream1.filter(i->i>2).map(i->i*2).skip(2).limit(2).reduce(Integer::sum)); System.out.println(stream1.filter(i->i>2).mapToInt(i->i*2).skip(2).limit(2).sum());//32 无则为0 System.out.println("------------------------"); // System.out.println(stream1.filter(i->i>200).mapToInt(i->i*2).skip(2).limit(2).min()); stream2.filter(i->i>2).mapToInt(i->i*2).skip(2).limit(2).min(). ifPresent(System.out::println);//14 System.out.println("------------------------"); IntSummaryStatistics intSummaryStatistics = stream3.filter(i->i>2).mapToInt(i->i*2).skip(2).limit(2).summaryStatistics(); System.out.println(intSummaryStatistics.getMax());//18 System.out.println(intSummaryStatistics.getAverage());//16.0 System.out.println(intSummaryStatistics.getMin());//14 }
- 对已经进行操作过的流对象不能再进行操作,可以对新创建的流对象进行操作
有终止操作,才对流开始计算操作@Test public void TestRepeat(){ Stream<Integer> stream = Stream.iterate(1, i->i+2).limit(5);//创建新的流 System.out.println(stream); Stream<Integer> stream1 = stream.filter(i->i>2);//对流操作,创建新的流 System.out.println(stream1); //对已操作过的流stream不能直接进行操作,对新的流对象stream1进行操作 Stream<Integer> stream2 = stream1.distinct(); System.out.println(stream2); } @Test public void TestRepeat2(){ List<String> list = Arrays.asList("hello","word","hello world"); List<String> list1 = Arrays.asList("hello","word","hello world"); list.stream().map(i->i.substring(0,1).toUpperCase() + i.substring(1)).forEach(System.out::println); System.out.println("----------------"); Stream<String> stringStream = list1.stream().map(i-> { String result = i.substring(0,1).toUpperCase() + i.substring(1); System.out.println("test"); return result; });//中间操作,需要有终止操作才能倒着完成中间的操作 // stringStream.forEach(System.out::println); System.out.println("----------------"); IntStream.iterate(0, i->(i+1)%2).limit(6).distinct().forEach(System.out::println);//正常 // IntStream.iterate(0, i->(i+1)%2).distinct().limit(6).forEach(System.out::println);//不停的运行 }
- 外部迭代与内部迭代(图片源自网络)
- 代码示例:
@Test public void TestParallel(){ List<String> list = new ArrayList<>(5000000); for(int i=0;i<5000000;i++){ list.add(UUID.randomUUID().toString()); } System.out.println("开始排序"); long starttime = System.nanoTime(); list.stream().sorted().count(); long endtime = System.nanoTime(); long millis = TimeUnit.NANOSECONDS.toMillis(endtime-starttime); System.out.println("排序耗时:" + millis); System.out.println("开始排序"); starttime = System.nanoTime(); list.parallelStream().sorted().count();//并行 endtime = System.nanoTime(); millis = TimeUnit.NANOSECONDS.toMillis(endtime-starttime); System.out.println("排序耗时:" + millis); } @Test public void TestPrinciple(){ // 对流进行操作,一个操作容器,并对操作串行化,即对流的每个元素进行短路操作 // 实现:输出集合中第一个长度为5的字符串 List<String> list = Arrays.asList("Hello1","world","Liu LIU"); list.stream().mapToInt(i->{ int length = i.length(); System.out.println(i); return length; }).filter(i->i == 5). findFirst().ifPresent(System.out::println);//输出: Hello 5 } @Test public void Test(){ // 实现:得到将集合中所有元素且无重复 List<String> list = Arrays.asList("Hello","Hello world", "welcome the Hello world","Hello welcome"); list.stream().map(item -> item.split(" ")).distinct(). collect(Collectors.toList()).forEach(System.out::println); //不可取,返回四个String[] //需要使用flatMap:distinct去重或用Set(无重复元素) List<String> result = list.stream().map(item -> item.split(" ")). flatMap(Arrays::stream).distinct().collect(Collectors.toList()); Set<String> strings = list.stream().map(item -> item.split(" ")). flatMap(Arrays::stream).collect(Collectors.toCollection(TreeSet::new)); result.stream().forEach(System.out::println);//输出:Hello world welcome the System.out.println("-----------------------"); strings.stream().forEach(System.out::println);//输出:Hello world welcome the } @Test public void Test1(){ // 实现:list1+list2 交叉叠加输出(不同放式和不同人打招呼) List<String> list1 = Arrays.asList("Hello","Hi"); List<String> list2 = Arrays.asList("zhong hua","tian men","liu jia"); List<String> stringList = list1.stream().flatMap(i->list2.stream(). map(i2->i + " " + i2)).collect(Collectors.toList()); stringList.forEach(System.out::println); }
概念理解:
集合关注的是数据与数据存储本身
流关注的这是对数据的计算
流与迭代器类似的一点是:流是无法重复使用或消费的
中间操作都会返回一个Stream对象
终止操作则不会返回Stream类型,可能不返回值,也可能返回其他类型的单个值
流的短路:对流进行操作时,对每个元素进行操作容器里的操作;很多个操作,但对流中元素只进行了一次迭代。
- 流中的分组(与SQL语句非常像)、分区(只有两组):
图片来自网络public class StreamGroupingTest { @Test public void TestGrouping(){ // 分组与分区功能的实现(可与SQL语句对比) SomePerson somePerson1 = new SomePerson("liuliu", 21,100 ); SomePerson somePerson2 = new SomePerson("tian", 11,100 ); SomePerson somePerson3 = new SomePerson("men", 11,100 ); SomePerson somePerson4 = new SomePerson("tian", 30,110 ); List<SomePerson> somes = Arrays.asList(somePerson1,somePerson2,somePerson3,somePerson4); //按姓名分 Map<String,List<SomePerson>> mapName = somes.stream(). collect(Collectors.groupingBy(SomePerson::getName)); //按高度分 Map<Integer,List<SomePerson>> mapHeigt = somes.stream(). collect(Collectors.groupingBy(SomePerson::getHeight)); //按高度分,且统计个数 Map<Integer,Long> mapAndCount = somes.stream(). collect(Collectors.groupingBy(SomePerson::getHeight, Collectors.counting())); //按姓名分,且统计高度相关信息 Map<String,Double> mapNameAndCompute = somes.stream().collect(Collectors. groupingBy(SomePerson::getName, Collectors.averagingInt(SomePerson::getHeight))); //分区 Map<Boolean,List<SomePerson>> mapTwo = somes.stream().collect(Collectors. partitioningBy(s->s.getAge() >= 20)); System.out.println(mapName); System.out.println(mapHeigt); System.out.println(mapAndCount);//输出: {100=3, 110=1} System.out.println(mapNameAndCompute);//输出:{tian=105.0, men=100.0, liuliu=100.0} System.out.println(mapTwo); mapTwo.get(true).forEach(i-> System.out.println(i.getAge()));//输出:21 30 } } class SomePerson{ private String name; private int age; private int height; public SomePerson(String name, int age, int height) { this.name = name; this.age = age; this.height = height; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } }
JAVA新特性(3)stream的理解与使用
最新推荐文章于 2024-04-23 10:18:49 发布