Java Stream的基本概念以及创建方法
前言
相信很多人(包括我自己),在很长一段时间内虽然使用了JDK1.8,却从来没有使用过自1.8开始增加的Stream这一强大使用的新特性,本文则将先从如何创建Stream开始,逐步去学会Stream的使用。本文不会涉及对流中数据的操作,而只讨论创建流的几种方法,以及一些基础概念,关于流的实用操作将会在后续文章中一一介绍。
Stream与Collection的区别
1.用途与关注点不同
Collection主要关注于对象的存储方面,通过使用List、Map、Set等等数据结构,让数据被更好的组织起来,以便于使用。而Stream则关注于对象的操作方面,包含reduce、map、filter等等实用的操作。
2.流是懒搜索(Laziness-seeking)的
先看一个例子,考虑一下代码:
Randomrandom=newRandom(29); random.ints() .filter(v->v>5&&v<31) .limit(3) .forEach(System.out::println); //output: //21 //22 //28
代码首先创建了一个随机整数流,然后过滤得到其中在(5,31)范围内的数,最终得到其中的3个数并输出,这里创建的流就是3中所说的无限流,而流在执行的过程中一旦得到一个满足条件的整数就会加到结果序列中,并且开始进行下一轮的搜索,直到找到3个满足的整数为止。流只会完成所给任务(找到3个满足指定范围的整数并输出),不会有额外的操作。
3.流的大小可以是无限的
尽管Collection的数据量也可以动态扩展改变,但由于计算机内存是有限的,所以其数据量大小始终可以看成只能为有限的大小。但Stream则不同,由于流是懒加载的,所以当使用limit类似的短路操作时,就可以利用特性2的原因去接收一个无限流。
4.流操作不存在副作用
和Collection中的某些操作,例如remove会删除集合中的元素不同,流不会修改生成流的原有集合中的数据,例如使用filter时,会产生一个经过元素过滤后的新流,而不会修改原集合中的数据。
5.流属于消耗品(Consumable)
不同与Collection没有访问次数与使用的限制,一个流在其生命周期中只能被执行一次,当执行了终端操作(terminaloperation,在之后的文章中会具体介绍)后,即使没有将流关闭,例如上述代码中的forEach,也无法再次访问了(类似迭代器),如下代码所示,想要再操作,必须重新创建一个流。
IntStreamstream=newRandom(29).ints(); stream.filter(v->v>5&&v<31) .limit(3) .forEach(System.out::println); //当执行了终端操作后再使用,就会出现一下异常提示信息 //java.lang.IllegalStateException:streamhasalreadybeenoperateduponorclosed stream.forEach(System.out::println);
创建流
流可以通过很多种方式被创建,下面进行一一介绍:
1.Collection家族创建的方式
对于实现了Collection接口的类,都可以通过stream()和parallelStream()创建对应流,如下代码所示:
Listlist=newArrayList<>(Arrays.asList(1,2,3,4,5)); //创建一个普通的流 Stream stream=list.stream(); //创建一个并行流 Stream parallelStream=list.parallelStream();
2.数组家族创建的方式
对于数组类型的元素,都可以使用Arrays类的stream()创建对应的流,如果想获得并行流则需要使用parallel()方法,如下所示:
IntStreamstream=Arrays.stream(newint[]{1,2,3}); //生成流对应的并行流 IntStreamparallelStream=stream.parallel();
3.Stream家族的工厂方法
通过工厂方法来创建流的方式比较多,可以通过empty、of、concat、generate、iterate、range、rangeClosed以及builder等方法创建流,下面就通过代码样例来一一介绍:
//产生一个不包含任何元素的流 Stream
4.IO/NIO家族中的方法
除了两种获取lines生成的流外,其它几种方式都很少使用,这一部分了解即可。
try{ Stringdir=System.getProperty("user.dir"); //以下两种方法均是获取文件中行数据组成的流 Streamstream1=newBufferedReader(newFileReader(dir+"\\demo.txt")).lines(); Stream stream2=Files.lines(Paths.get(dir+"\\demo.txt")); //获取指定路径下所有文件/文件夹的路径组成的流 Stream stream3=Files.list(Paths.get("d:\\temp")); //获取指定路径下以及指定最深文件层级内(在这里为2)且满足函数条件的所有文件/文件夹的路径组成的流 Stream stream4=Files.find( Paths.get("d:\\temp"),1,(path,basicFileAttributes)->path.isAbsolute()); //获取指定路径下以及指定最深文件层级内(在这里为2)所有文件/文件夹的路径组成的流 Stream stream5=Files.walk(Paths.get("d:\\temp"),2); }catch(IOExceptione){ e.printStackTrace(); }
5.Random获取流的方式
由于直接使用Random类生成随机数无限流,均为基本数据类型组成的流,因此通常还需要使用boxed方法进行装箱(以前凡是生成的为IntStream,DoubleStream,LongStream均同此),以便可以使用更加丰富的特性。
Randomrandom=newRandom(); //以下三种方式得到的均是随机数组成的<无限流> IntStreamstream1=random.ints(); DoubleStreamstream2=random.doubles(); LongStreamstream3=random.longs(); StreamboxedStream=stream1.boxed();
下面就先举一个具体的实用的例子,在之后的文章中会详细介绍一些实用操作,这里可以先做了解:
//对数组元素进行倒序排序 //如果不进行装箱(boxed)处理,则只能使用默认的升序排序方法 //通过装箱,则可以通过自定义比较器,实现更加多样的排序 int[]arr={1,5,4,6,3,9,4,5,6,4}; int[]reverseArr=Arrays.stream(arr) .boxed() .sorted(Comparator.reverseOrder()) .mapToInt(Integer::valueOf) .toArray(); //output:[9,6,6,5,5,4,4,4,3,1] System.out.println(Arrays.toString(reverseArr));
6.其它可以生成流的类
除了以上介绍的几个主要可以生成流的类之外,还有一些其它不太常见的可以流的类,下面是部分代码展示:
Strings="1,2,3,4,5,6,7"; //由分割后的字符串组成的流 //在这里就是"1","2","3","4","5","6","7"组成的流 Streamstream1=Pattern.compile(",").splitAsStream(s); BitSetbitSet=newBitSet(); for(inti=0;i<10;i++){ if(i%2==0){ bitSet.set(i); } } //由bitset中被设置为true的位下标所组成的流 //在这里就是0,2,4,6,8 IntStreamstream2=bitSet.stream(); try{ Stringdir=System.getProperty("user.dir"); JarFilejarFile=newJarFile(dir+"\\demo.jar"); //由指定jar包中所有文件及文件夹的JarEntry对象所组形成的流 Stream stream3=jarFile.stream(); }catch(IOExceptione){ e.printStackTrace(); }
此外还可以通过StreamSupport工具类进行产生和操作流,由于本文包括之后的文章主要是为了入门和先简单上手,所以这里不做详细讨论,感兴趣的可以自己进行查阅资料。
总结
本文简单介绍了Stream这个自1.8开始引入的新特性,然后简单介绍了一些基本概念和流的创建方式,在接下来的文章中还会介绍流的一些实用操作,希望能和大家一起学会使用Stream这个实用的特性,当然本文也难免有错误之处,希望得到各位的指正。
以上就是JavaStream的基本概念以及创建方法的详细内容,更多关于JAVAStream的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。