jdk8新特性四: jdk8Stream流操作
发布日期:2021-05-28 16:44:50 浏览次数:11 分类:技术文章

本文共 11438 字,大约阅读时间需要 38 分钟。

jdk8新特性五: jdk8Stream流操作

文章目录

jdk8之流Stream

  1. Stream,中文称为流,通过将集合转换为这么一种叫做流的元素队列,通过声明性方式,能够对集合中的每个元素进行一系列并行和串行的流水线操作。
  2. 元素是特定类型的对象,所以元素集合看作一种流,流在管道中传输,且可以在管道的节点上进行处理。比如排序,聚合,过滤等操作。

stream流的执行顺序

  1. 操作详情:

1、数据元素便是原始集合,如list,set,map集合。

2、生成流,可以是串行流,stream()或者是并行流parallelStream()

3、中间操作:可以是排序,聚合,过滤,转换。

4、终端操作:很多流操作本身就会返回一个流,所以多个操作可以直接连接起来,最后统一进行收集。

  1. 例子

stream().map()是将一个元素映射成另一个元素。stream是生成流,map是中间操作。

collect()是终端操作。

List
list=Arrays.asList("spring","abc","bcd","amd","efo");List
resultList = list.stream().map(obj -> "在小d课堂学习" + obj).collect(Collectors.toList());System.out.println(resultList);

stream中的函数

  1. map函数

1、将流中每个元素T映射为R(类似类型转换)

2、使用场景:在javaweb中将do对象转成dto对象。

public static void main(String[] args) throws IOException, InterruptedException {
List
list=Arrays.asList(new User(1,"小的","123"),new User(21,"小c","1234"),new User(31,"小d","1233"), new User(4,"小的m","1d23"),new User(21,"小d的","12d3")); List
resultDto = list.stream().map(obj -> {
UserDto userDto = new UserDto(); userDto.setUserId(obj.getId()); userDto.setUsername(obj.getName()); return userDto; }).collect(Collectors.toList()); System.out.println(resultDto);}
  1. filter函数

1、用于通过设置的条件过滤出元素

2、例如:过滤出字符串长度大于5的字符串

List
list2 = Arrays.asList("springboot", "springcloud", "redis", "git", "netty", "java", "html", "docker");List
resultList = list2.stream().filter(obj -> obj.length() > 5).collect(Collectors.toList());System.out.println(resultList);
  1. limit函数和sorted函数
List
resultList = list2.stream().sorted().collect(Collectors.toList());List
resultList = list2.stream().sorted(Comparator.comparing(obj->obj.length())).collect(Collectors.toList());List
resultList = list2.stream().sorted(Comparator.comparing(obj->obj.length(),Comparator.reverseOrder())).collect(Collectors.toList());List
resultList = list2.stream().sorted(Comparator.comparing(String::length).reversed()).collect(Collectors.toList());List
resultList = list2.stream().sorted(Comparator.comparing(String::length)).limit(3).collect(Collectors.toList());System.out.println(resultList);
  1. allMatch函数

检查是否匹配所有元素,只有全部符合才返回true

List
list = Arrays.asList("springboot", "springcloud", "redis", "git", "netty", "java", "html", "docker");boolean flag = list.stream().allMatch(obj->obj.length()>1);System.out.println(flag);
  1. anyMatch函数

检查是否至少匹配一个元素。

List
list = Arrays.asList("springboot", "springcloud", "redis", "git", "netty", "java", "html", "docker");boolean flag = list.stream().anyMatch(obj->obj.length()>18);System.out.println(flag);
  1. Max函数和Min函数,比较出最大值和最小值。

Optional是新增的类型,可以进行判空操作。

if(xxx.isPresent()){}

public static void main(String[] args) throws IOException, InterruptedException {
List
list = Arrays.asList(new Student(32),new Student(33),new Student(21),new Student(29),new Student(18)); //list.stream().max(Comparator.comparingInt(Student::getAge)); //最⼤ Optional
optional2 = list.stream().max((s1, s2)-> Integer.compare(s1.getAge(),s2.getAge())); //最⼩ Optional
optional = list.stream().min((s1, s2)-> Integer.compare(s1.getAge(),s2.getAge())); System.out.println(optional2.get().getAge()); System.out.println(optional.get().getAge());}

jdk8里面的并行流parallelStream

  1. 集合做重复操作,如果使用串行执行,会相当耗时,因此一般会采用多线程加快,java8的paralleStream用forkjoin框架提供并发执行能力。
  2. 底层原理

线程池ForkjoinPool维护一个线程队列

可以分割任务,将父任务拆分成子任务,完全贴合分治思想。

  1. 问题:

并行流,不一定比串行流块,当数据量小的时候,并行流还没把任务分出去,说不一定串行流已经执行完了。

可能会出现线程安全问题。

  1. 线程安全问题例子

ArrayList()是不安全的,会报异常。

CopyOnwriteArrayList():是安全的。上了锁。

for(int i=0;i<10;i++) {
List list2 = new ArrayList(); //List list = new CopyOnWriteArrayList(); IntStream.range(0, 100).parallel().forEach(list2::add); System.out.println(list2.size());}

jdk8里面的聚合操作reduce

  1. reduce,聚合,就是根据一定的规则将Stream中的元素进行计算后返回一个唯一的值。
int value = Stream.of(1, 2, 3, 4, 5).reduce((item1, item2) -> item1                                            + item2).get();
  1. 如果不用lambda,就要使用匿名函数。
int result = Stream.of(1,2,3,4,5).reduce(new                                         BinaryOperator
() {
@Override public Integer apply(Integer item1, Integer item2) {
return item1 + item2; } }).get();
  1. 可以设置一个初始值
int value = Stream.of(1, 2, 3, 4,5).reduce(100, (sum, item) -> sum +                                           item);
  1. 利用聚合reduce求最大值
int value = Stream.of(1645, 234345, 32,44434,564534,435,34343542,212).reduce( (item1, item2) -> item1 >item2 ? item1 : item2 ).get();System.out.println(value);

jdk8的forEach集合

  1. forEach就是遍历每一个元素,在forEach里面进行对每一个元素进行操作。map也有这种功能。
  2. 注意点:

1、不能修改包含外部的变量的值。

2、不能用break或者return或者continue等关键字结束或者循环。

jdk8收集器和集合统计

  1. Collectors.collect()方法 的使用

一个终端操作,用于对流中的数据进行归集操作,collect方法接收的参数是一个Collector

//源代码public static 
Collector
> toList() {
return new CollectorImpl<>((Supplier
>)ArrayList::new, List::add,(left, right) -> {
left.addAll(right); return left; }, CH_ID);}

ArrayList::new,创建⼀个ArrayList作为累加器

List::add,对流中元素的操作就是直接添加到累加器中

reduce操作, 对⼦任务归集结果addAll,后⼀个⼦任务的结果直接全部添加到

前⼀个⼦任务结果中

CH_ID 是⼀个unmodififiableSet集合

Collectors.toMap()

Collectors.toSet()

Collectors.toCollection() :⽤⾃定义的实现Collection的数据结构收集

Collectors.toCollection(LinkedList::new)

Collectors.toCollection(CopyOnWriteArrayList::new)

Collectors.toCollection(TreeSet::new)

  1. 拼接函数Collectors.joining
  • 共有三个重载方法

//3种重载⽅法

Collectors.joining()

Collectors.joining(“param”)

Collectors.joining(“param1”, “param2”, “param3”)

该⽅法可以将Stream得到⼀个字符串, joining函数接受三个参数,分别表示 元素之间的连

接符、前缀和后缀。

List
list=Arrays.asList("abc","bcd","cmd");String result = list.stream().collect(Collectors.joining(","));System.out.println(result);
  • 添加前缀和后缀
String result = Stream.of("springboot", "mysql", "html5",                          "css3").collect(Collectors.joining(",", "[", "]"));
  1. jdk8里面partitioningBy分组
  • Collectors.partitioningBy分组,key是boolean类型
//源码====predicate是断言public static 
Collector
>> partitioningBy(Predicate
predicate) {
return partitioningBy(predicate, toList());}
  • 需求:根据list进行分组,字符串长度大于4的为一组,其他为一组。
List
list = Arrays.asList("java", "springboot","HTML5","nodejs","CSS3");Map
> result =list.stream().collect(partitioningBy(obj -> obj.length() > 4));
  1. group By分组
  • Collectors.groupingBy()

  • 需求:根据学生所在的省份,进行分组

List
students = Arrays.asList(new Student("⼴东", 23), new Student("⼴东", 24), new Student("⼴东", 23),new Student("北京", 22), new Student("北京", 20), new Student("北京", 20),new Student("海南", 25));Map
> listMap =students.stream().collect(Collectors.groupingBy(obj ->obj.getProvince()));listMap.forEach((key, value) -> {
System.out.println("========"); System.out.println(key); value.forEach(obj -> {
System.out.println(obj.getAge()); });});class Student {
private String province; private int age; public String getProvince() {
return province; } public void setProvince(String province) {
this.province = province; } public int getAge() {
return age; } public void setAge(int age) {
this.age = age; } public Student(String province, int age) {
this.age = age; this.province = province; }}
  1. Collectors.counting()统计
  • 需求:统计各个省份的人数
List
students = Arrays.asList(new Student("⼴东", 23), new Student("⼴东", 24), new Student("⼴东", 23),new Student("北京", 22), new Student("北京", 20), new Student("北京", 20),new Student("海南", 25));Map
listMap =students.stream().collect(Collectors.groupingBy(Student::getProvince,Collectors.counting()));listMap.forEach((key, value) -> {
System.out.println(key+"省⼈数有 "+value);});
  1. 统计平均值,最大值,最小值等。
  • Collectors.summarizing()
public static 
Collector
summarizingInt(ToIntFunction
mapper) {
return new CollectorImpl
( IntSummaryStatistics::new, (r, t) -> r.accept(mapper.applyAsInt(t)), (l, r) -> {
l.combine(r); return l; }, CH_ID); }
  • 分类

summarizingInt

summarizingLong

summarizingDouble

List
students = Arrays.asList(new Student("⼴东", 23), newStudent("⼴东", 24), new Student("⼴东", 23),new Student("北京", 22), newStudent("北京", 20), new Student("北京", 20),new Student("海南", 25));IntSummaryStatistics summaryStatistics =students.stream().collect(Collectors.summarizingInt(Student::getAge));System.out.println("平均值:" + summaryStatistics.getAverage());System.out.println("⼈数:" + summaryStatistics.getCount());System.out.println("最⼤值:" + summaryStatistics.getMax());System.out.println("最⼩值:" + summaryStatistics.getMin());System.out.println("总和:" + summaryStatistics.getSum());class Student {
private String province; private int age; public String getProvince() {
return province; } public void setProvince(String province) {
this.province = province; } public int getAge() {
return age; } public void setAge(int age) {
this.age = age; } public Student(String province, int age) {
this.age = age; this.province = province; }}

jdk8新内存空间Metaspace

  1. HostSpot虚拟机新增了内存空间Metaspace

  2. jdk8中的永久代被取消了。

JVM内存知识 在JDK8之前的HotSpot JVM,有个区域叫做“永久代(permanent generation), 通过

在命令⾏设置参数-XX:MaxPermSize来设定永久代最⼤可分配的内存空间
如果JDK8⾥⾯设置了PermSize 和 MaxPermSize 会被忽略并给出警告

  1. 永久代的作用

该块内存主要是被JVM⽤来存放 class 和 mate 信息的,当 class 被加载 loader 的时候就会

被存储到该内存区中,如⽅法的编译信息及字节码、常量池和符号解析、类的层级信息,字段,名

字等

永久代空间不够,类信息太多,会报oom

  1. jdk8的处理

jdk8的修改 JDK8 HotSpot JVM 使⽤本地内存来存储类元数据信息,叫做 元空间(Metaspace)

在默认情况下Metaspace的⼤⼩只与本地内存⼤⼩有关

常⽤的两个参数 -XX:MetaspaceSize=N 指Metaspace扩容时触发FullGC的初始化阈值

-XX:MaxMetaspaceSize=N 指⽤于限制Metaspace增⻓的上限,防⽌因为某些情况导致

Metaspace⽆限的使⽤本地内存

不管两个参数如何设置,都会从20.8M开始,然后随着类加载越来越多不断扩容调整直到最⼤

  1. 查看Metaspace大小命令

jstat -gc pid MC: current metaspace capacity MU: mateaspace utilization

MC:Metaspace的容量空间

MU:Metaspace的已经使用空间。

jdk7里面的新特性try-with-resources

  1. 在try( …)⾥声明的资源,会在try-catch代码块结束后⾃动关闭掉
  2. 旧的写法
public static void main(String[] args) throws IOException {
String path = "/Users/jack/Desktop/t.txt"; test(path);}private static void test(String filepath) throws FileNotFoundException {
OutputStream out = new FileOutputStream(filepath); try {
out.write((filepath+"可以学习java架构课程").getBytes()); } catch (Exception e) {
e.printStackTrace(); }finally {
try {
out.close(); } catch (IOException e) {
e.printStackTrace(); } }}
  1. 新的写法
private static void test(String filepath){
try(OutputStream out = new FileOutputStream(filepath);) {
out.write((filepath+"可以学习java架构课程").getBytes()); } catch (Exception e) {
e.printStackTrace(); }}
  1. 注意点

1、实现了AutoCloseable接⼝的类,在try()⾥声明该类实例的时候,try结束后⾃动调⽤的

close⽅法,这个动作会早于finally⾥调⽤的⽅法
2、不管是否出现异常,try()⾥的实例都会被调⽤close⽅法

3、try⾥⾯可以声明多个⾃动关闭的对象,越早声明的对象,会越晚被close掉

转载地址:https://blog.csdn.net/qq_33322074/article/details/105703765 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:java基础:IO流大总结
下一篇:Jdk8新特性三:jdk8之函数式编程Function

发表评论

最新留言

感谢大佬
[***.8.128.20]2024年02月27日 08时01分21秒