本文共 11438 字,大约阅读时间需要 38 分钟。
jdk8新特性五: jdk8Stream流操作
文章目录
jdk8之流Stream
- Stream,中文称为流,通过将集合转换为这么一种叫做流的元素队列,通过声明性方式,能够对集合中的每个元素进行一系列并行和串行的流水线操作。
- 元素是特定类型的对象,所以元素集合看作一种流,流在管道中传输,且可以在管道的节点上进行处理。比如排序,聚合,过滤等操作。
- 操作详情:
1、数据元素便是原始集合,如list,set,map集合。
2、生成流,可以是串行流,stream()或者是并行流parallelStream()
3、中间操作:可以是排序,聚合,过滤,转换。
4、终端操作:很多流操作本身就会返回一个流,所以多个操作可以直接连接起来,最后统一进行收集。
- 例子
stream().map()是将一个元素映射成另一个元素。stream是生成流,map是中间操作。
collect()是终端操作。
Listlist=Arrays.asList("spring","abc","bcd","amd","efo");List resultList = list.stream().map(obj -> "在小d课堂学习" + obj).collect(Collectors.toList());System.out.println(resultList);
stream中的函数
- map函数
1、将流中每个元素T映射为R(类似类型转换)
2、使用场景:在javaweb中将do对象转成dto对象。
public static void main(String[] args) throws IOException, InterruptedException { Listlist=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);}
- filter函数
1、用于通过设置的条件过滤出元素
2、例如:过滤出字符串长度大于5的字符串
Listlist2 = 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);
- limit函数和sorted函数
ListresultList = 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);
- allMatch函数
检查是否匹配所有元素,只有全部符合才返回true
Listlist = Arrays.asList("springboot", "springcloud", "redis", "git", "netty", "java", "html", "docker");boolean flag = list.stream().allMatch(obj->obj.length()>1);System.out.println(flag);
- anyMatch函数
检查是否至少匹配一个元素。
Listlist = Arrays.asList("springboot", "springcloud", "redis", "git", "netty", "java", "html", "docker");boolean flag = list.stream().anyMatch(obj->obj.length()>18);System.out.println(flag);
- Max函数和Min函数,比较出最大值和最小值。
Optional是新增的类型,可以进行判空操作。
if(xxx.isPresent()){}
public static void main(String[] args) throws IOException, InterruptedException { Listlist = 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
- 集合做重复操作,如果使用串行执行,会相当耗时,因此一般会采用多线程加快,java8的paralleStream用forkjoin框架提供并发执行能力。
- 底层原理
线程池ForkjoinPool维护一个线程队列
可以分割任务,将父任务拆分成子任务,完全贴合分治思想。
- 问题:
并行流,不一定比串行流块,当数据量小的时候,并行流还没把任务分出去,说不一定串行流已经执行完了。
可能会出现线程安全问题。
- 线程安全问题例子
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
- reduce,聚合,就是根据一定的规则将Stream中的元素进行计算后返回一个唯一的值。
int value = Stream.of(1, 2, 3, 4, 5).reduce((item1, item2) -> item1 + item2).get();
- 如果不用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();
- 可以设置一个初始值
int value = Stream.of(1, 2, 3, 4,5).reduce(100, (sum, item) -> sum + item);
- 利用聚合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集合
- forEach就是遍历每一个元素,在forEach里面进行对每一个元素进行操作。map也有这种功能。
- 注意点:
1、不能修改包含外部的变量的值。
2、不能用break或者return或者continue等关键字结束或者循环。
jdk8收集器和集合统计
- Collectors.collect()方法 的使用
一个终端操作,用于对流中的数据进行归集操作,collect方法接收的参数是一个Collector
//源代码public staticCollector > 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)
- 拼接函数Collectors.joining
- 共有三个重载方法
//3种重载⽅法
Collectors.joining()
Collectors.joining(“param”)
Collectors.joining(“param1”, “param2”, “param3”)
该⽅法可以将Stream得到⼀个字符串, joining函数接受三个参数,分别表示 元素之间的连
接符、前缀和后缀。
Listlist=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(",", "[", "]"));
- jdk8里面partitioningBy分组
- Collectors.partitioningBy分组,key是boolean类型
//源码====predicate是断言public staticCollector >> partitioningBy(Predicate predicate) { return partitioningBy(predicate, toList());}
- 需求:根据list进行分组,字符串长度大于4的为一组,其他为一组。
Listlist = Arrays.asList("java", "springboot","HTML5","nodejs","CSS3");Map > result =list.stream().collect(partitioningBy(obj -> obj.length() > 4));
- group By分组
-
Collectors.groupingBy()
-
需求:根据学生所在的省份,进行分组
Liststudents = 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; }}
- Collectors.counting()统计
- 需求:统计各个省份的人数
Liststudents = 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);});
- 统计平均值,最大值,最小值等。
- Collectors.summarizing()
public staticCollector 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
Liststudents = 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
-
HostSpot虚拟机新增了内存空间Metaspace
-
jdk8中的永久代被取消了。
JVM内存知识 在JDK8之前的HotSpot JVM,有个区域叫做“永久代(permanent generation), 通过
在命令⾏设置参数-XX:MaxPermSize来设定永久代最⼤可分配的内存空间 如果JDK8⾥⾯设置了PermSize 和 MaxPermSize 会被忽略并给出警告
- 永久代的作用
该块内存主要是被JVM⽤来存放 class 和 mate 信息的,当 class 被加载 loader 的时候就会
被存储到该内存区中,如⽅法的编译信息及字节码、常量池和符号解析、类的层级信息,字段,名
字等
永久代空间不够,类信息太多,会报oom
- jdk8的处理
jdk8的修改 JDK8 HotSpot JVM 使⽤本地内存来存储类元数据信息,叫做 元空间(Metaspace)
在默认情况下Metaspace的⼤⼩只与本地内存⼤⼩有关
常⽤的两个参数 -XX:MetaspaceSize=N 指Metaspace扩容时触发FullGC的初始化阈值
-XX:MaxMetaspaceSize=N 指⽤于限制Metaspace增⻓的上限,防⽌因为某些情况导致
Metaspace⽆限的使⽤本地内存
不管两个参数如何设置,都会从20.8M开始,然后随着类加载越来越多不断扩容调整直到最⼤
- 查看Metaspace大小命令
jstat -gc pid MC: current metaspace capacity MU: mateaspace utilization
MC:Metaspace的容量空间
MU:Metaspace的已经使用空间。
jdk7里面的新特性try-with-resources
- 在try( …)⾥声明的资源,会在try-catch代码块结束后⾃动关闭掉
- 旧的写法
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(); } }}
- 新的写法
private static void test(String filepath){ try(OutputStream out = new FileOutputStream(filepath);) { out.write((filepath+"可以学习java架构课程").getBytes()); } catch (Exception e) { e.printStackTrace(); }}
- 注意点
1、实现了AutoCloseable接⼝的类,在try()⾥声明该类实例的时候,try结束后⾃动调⽤的
close⽅法,这个动作会早于finally⾥调⽤的⽅法 2、不管是否出现异常,try()⾥的实例都会被调⽤close⽅法3、try⾥⾯可以声明多个⾃动关闭的对象,越早声明的对象,会越晚被close掉
转载地址:https://blog.csdn.net/qq_33322074/article/details/105703765 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!