一、方法引用与构造函数引用
- 说明:方法引用是⼀种更简洁易懂的lambda表达式,操作符是双冒号::,用来直接访问类或者实例已经存在的方法或构造方法
- 通过方法引用,可以将方法的引⽤赋值给⼀个变量
- 语法:左边是容器(可以是类名,实例名),中间是" :: ",右边是相应的方法名
- 静态方法,则是ClassName::methodName。如 Object ::equals
- 实例方法,则是Instance::methodName
- 构造函数,则是 类名::new;
- 单个参数
Function<入参1, 返回类型> func = 方法引用
应用 func.apply(入参); - 两个参数
BiFunction<入参1,入参2, 返回类型> func = 方法引用
应用 func.apply(入参1,入参2);
class User {
private String username;
private Integer age;
public User() {}
public User(String username) {
this.username = username;
}
public User(String username, Integer age) {
this.username = username;
this.age = age;
}
}
public class Test{
public static void main(String[] args) {
// 使用双冒号::来构造静态函数引用
Function<String, Integer> fun = Integer::parseInt;
Integer value = fun.apply("1024");
System.out.println(value);
// 使用双冒号::来构造非静态函数引用
String content = "测试使用";
Function<Integer, String> func = content::substring;
String result = func.apply(1);
System.out.println(result);
// 构造函数引用,多个参数
BiFunction<String, Integer, User> biFunction = User::new;
User user1 = biFunction.apply("Test", 28);
System.out.println(user1.toString());
//构造函数引用,单个参数
Function<String, User> function = User::new;
User user2 = function.apply("Test");
System.out.println(user2.toString());
// 函数引用也是一种函数式接用,可以将函数引用作为方法的参数
sayHello(String::toUpperCase, "Test");
}
/**
*
* @param func 函数引用
* @param param 对应的参数
*/
private static void sayHello(Function<String, String> func, Stringparam) {
String result = func.apply(param);
System.out.println(result);
}
}
二、JDK8之流Stream
- Stream 中文称为 “流”,通过将集合转换为这么⼀种叫做 “流”的元素队列,通过声明性方式,能够对集合中的每个元素进行⼀系列并行或串行的流水线操作。
-
元素是特定类型的对象,所以元素集合看作⼀种流, 流在管道中传输, 且可以在管道的节点上进行处理, ⽐如 排序,聚合,过滤等操作。
- 操作详情
- 数据元素便是原始集合,如List、Set、Map等
- 生成流,可以是串行流stream() 或者并行流 parallelStream()
- 中间操作,可以是 排序,聚合,过滤,转换等
- 终端操作,很多流操作本身就会返回⼀个流,所以多个操作可以直接连接起来,最后统⼀进行收集
List<String> list = Arrays.asList("aaaa","bbbb","cccc","dddd","eeee);
List<String> resultList = list.stream().map(obj->"遍历:"+obj).collect(Collectors.toList());
System.out.println(resultList);
三、JDK8之流操作map和filter函数
- map函数
- 将流中的每⼀个元素 T 映射为 R(类似类型转换)
- 类似遍历集合,对集合的每个对象做处理
- 场景:转换对象,如javaweb开发中集合里面的DO对象转换为DTO对象
List<String> list = Arrays.asList("aaaa","bbbb","cccc","dddd","eeee);
List<String> resultList = list.stream().map(obj->"遍历:"+obj).collect(Collectors.toList());
System.out.println(resultList);
@Data
class User {
private String name;
private Integer age;
public User(String name, Integer age) {
this.name= name;
this.age = age;
}
}
@Data
class UserDTO {
private String name;
private Integer age;
public User(String name, Integer age) {
this.name= name;
this.age = age;
}
}
public class Test{
public static void main(String[] args) {
List<User> list = Arrays.asList(new User("peter",11),new User("jack",12),new User("tom",10),new User("marry",14));
List<UserDTO> userDTOList = list.stream().map(obj->{
UserDTO userDTO = new UserDTO(obj.getName(),obj.getAage());
return userDTO;
}).collect(Collectors.toList());
System.out.println(userDTOList);
}
}
- filter函数
- 用于通过设置的条件过滤出元素
- 场景:主要用于筛选过滤出符合条件的元素
List<String> list = Arrays.asList("springboot", "springcloud","redis", "git", "netty", "java", "html", "docker");
List<String> resultList = list.stream().filter(obj -> obj.length() >5).collect(Collectors.toList());
System.out.println(resultList);
四、JDK8之流操作limit和sorted函数
- limit函数
- 截断流使其最多只包含指定数量的元素
List<String> list = Arrays.asList("springboot", "springcloud","redis", "git", "netty", "java", "html", "docker");
//limit截取
List<String> resultList=list.stream().sorted(Comparator.comparing(String::length).reversed()).limit(3).collect(Collectors.toList());
System.out.println(resultList);
- sorted函数
- sorted() 对流进⾏自然排序, 其中的元素必须实现Comparable 接口
- sorted(Comparator<? super T> comparator) 用来自定义升降序
List<String> list = Arrays.asList("springboot", "springcloud","redis", "git", "netty", "java", "html", "docker");
List<String> resultList1 = list.stream().sorted().collect(Collectors.toList());
List<String> resultList2 = list.stream().sorted(Comparator.comparing(obj -> obj.length())).collect(Collectors.toList());
List<String> resultList3 = list.stream().sorted(Comparator.comparing(obj ->obj.length(),Comparator.reverseOrder())).collect(Collectors.toList());
List<String> resultList4 = list.stream().sorted(Comparator.comparing(String::length).reversed()).collect(Collectors.toList());
五、JDK8之流操作allMatch和anyMatch函数
- allMatch函数
- 检查是否匹配所有元素,只有全部符合才返回true
List<String> list = Arrays.asList("springboot", "springcloud", "redis","git", "netty", "java", "html", "docker");
boolean flag = list.stream().allMatch(obj->obj.length()>1);
System.out.println(flag);
- anyMatch函数
- 检查是否⾄少匹配⼀个元素
List<String> list = Arrays.asList("springboot", "springcloud", "redis","git", "netty", "java", "html", "docker");
boolean flag = list.stream().anyMatch(obj->obj.length()>18);
System.out.println(flag)
六、JDK8之流操作max和min函数
- max和min函数
- 最大值和最小值
@Data
class Student {
private int age;
public Student(int age) {
this.age = age;
}
}
public class Test{
public static void main(String[] args) {
List<Student> list = Arrays.asList(new Student(32),newStudent(33),new Student(21),new Student(29),new Student(18));
//最大值
Optional<Student> optional = list.stream().max((s1, s2)->Integer.compare(s1.getAge(),s2.getAge()));
//最小值
Optional<Student> optional = list.stream().min((s1, s2)->Integer.compare(s1.getAge(),s2.getAge()));
System.out.println(optional.get().getAge());
}
}
七、JDK8之并行流parallelStream
- 为什么会有这个并行流
- 集合做重复的操作,如果使⽤串行执行会相当耗时,因此⼀般会采用多线程来加快, Java8的paralleStream用fork/join框架提供了并发执行能力。
- 底层原理
(1) 线程池(ForkJoinPool)维护⼀个线程队列
(2) 可以分割任务,将父任务拆分成子任务,完全贴合分治思想
//顺序输出
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
numbers.stream().forEach(System.out::println);
//并⾏乱序输出
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
numbers.parallelStream().forEach(System.out::println);
- paralleStream并行是否⼀定比Stream串行快?
- 错误,数据量少的情况,可能串行更快,ForkJoin会耗性能
- 多数情况下并行比串行快,是否可以都用并行
(1) 不行,部分情况会有线程安全问题,parallelStream里⾯使用的外部变量,比如集合⼀
定要使用线程安全集合,不然就会引发多线程安全问题。
for(int i=0;i<10;i++) {
//List list = new ArrayList();
List list = new CopyOnWriteArrayList();
IntStream.range(0, 100).parallel().forEach(list::add);
System.out.println(list.size());
}
八、JDK8之reduce操作
-
什么是reduce操作
- 聚合操作,中文意思是 “减少”
- 根据⼀定的规则将Stream中的元素进行计算后返回⼀个唯⼀的值
常用方法一
Optional<T> reduce(BinaryOperator<T> accumulator);
//accumulator 计算的累加器
//例子: 第⼀个元素相加和第⼆个元素相加,结果再和第三个元素相加,直到全部相加完成
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<Integer>() {
@Override
public Integer apply(Integer item1, Integer item2) {
return item1 + item2;
}
}).get();
- 常用方法二
T reduce(T identity, BinaryOperator<T> accumulator);
//identity ⽤户提供⼀个循环计算的初始值
//accumulator 计算的累加器
//例子: 100作为初始值,然后和第⼀个元素相加,结果在和第⼆个元素相加,直到全部相加完成
int value = Stream.of(1, 2, 3, 4,5).reduce(100, (sum, item) -> sum + item);
- 例子应用
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
- 集合遍历的方式
- for循环
- 迭代器 Iterator
- 注意点
- 不能修改包含外部的变量的值
- 不能用break或者return或者continue等关键词结束或者跳过循环
- Jdk8里面的新增接口
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
- 使用案例
List<Student> results = Arrays.asList("aaaa","bbbb","ccccc","ddddd","eeeee");
results.forEach(obj->{System.out.println(obj.toString());});
十、JDK8之collector收集器
- collect()方法的作用
- ⼀个终端操作, 用于对流中的数据进行归集操作,collect方法接受的参数是⼀个Collector
- 有两个重载方法,在Stream接口⾥⾯
//重载⽅法⼀
<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R>combiner);
//重载⽅法⼆
<R, A> R collect(Collector<? super T, A, R> collector);
- Collector的作用
- 就是收集器,也是⼀个接口, 它的工具类Collectors提供了很多工厂方法
- Collectors 的作用
- 工具类,提供了很多常见的收集器实现
(1)Collectors.toList()
- 工具类,提供了很多常见的收集器实现
//ArrayList::new,创建⼀个ArrayList作为累加器
// List::add,对流中元素的操作就是直接添加到累加器中reduce操作, 对⼦任务归集结果addAll,后⼀个子任务的结果直接全部添加到前⼀个子任务结果中
// CH_ID 是⼀个unmodifiableSet集合
public static <T> Collector<T, ?, List<T>> toList() {
return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,(left, right) -> {left.addAll(right); return left; }, CH_ID);
}
- Collectors.toMap()
- Collectors.toSet()
- Collectors.toCollection() :⽤⾃定义的实现Collection的数据结构收集
Collectors.toCollection(LinkedList::new)
Collectors.toCollection(CopyOnWriteArrayList::new)
Collectors.toCollection(TreeSet::new)
十一、JDK8之joining函数
- 拼接函数 Collectors.joining
//3种重载⽅法
Collectors.joining()
Collectors.joining("param")
Collectors.joining("param1", "param2", "param3")
- 其中⼀个的实现
public static Collector<CharSequence, ?, String> joining() {
return new CollectorImpl<CharSequence, StringBuilder, String>(
StringBuilder::new, StringBuilder::append,(r1, r2) -> { r1.append(r2); return r1; },StringBuilder::toString, CH_NOID);
}
- 该方法可以将Stream得到⼀个字符串, joining函数接受三个参数,分别表示 元素之间的连接符、前缀和后缀。
String result = Stream.of("springboot", "mysql", "html5","css3").collect(Collectors.joining(",", "[", "]"));
十二、JDK8之收集器 partitioningBy分组
- Collectors.partitioningBy 分组,key是boolean类型
public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? superT> predicate) {
return partitioningBy(predicate, toList());
}
- 例子: 根据list里面进行分组,字符串长度大于4的为⼀组,其他为另外⼀组
List<String> list = Arrays.asList("java", "springboot","HTML5","nodejs","CSS3");
Map<Boolean, List<String>> result = list.stream().collect(partitioningBy(obj -> obj.length() > 4));
十三、JDK8之收集器 group by分组
- 分组 Collectors.groupingBy()
public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function<?super T, ? extends K> classifier) {
return groupingBy(classifier, toList());
}
- 例子:根据学生所在的省份,进行分组
@Data
class Student {
private String province;
private int age;
public Student(String province, int age) {
this.age = age;
this.province = province;
}
}
public class Test{
public static void main(String[] args) {
List<Student> students = Arrays.asList(new Student("广东", 23), newStudent("广东", 24), new Student("广东", 23),new Student("北京", 22), new Student("北京", 20), new Student("北京", 20),new Student("海南", 25));
Map<String, List<Student>> listMap = students.stream().collect(Collectors.groupingBy(obj -> obj.getProvince()));
listMap.forEach((key, value) -> {
value.forEach(obj -> {
System.out.println(obj.getAge());
});
});
}
}
十四、JDK8之summarizing集合统计
- summarizing 统计相关, 下面是summarizingInt的源码
- 作用:可以⼀个方法把统计相关的基本上都完成
- 分类
- summarizingInt
- summarizingLong
- summarizingDouble
public static <T> Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper) {
return new CollectorImpl<T, IntSummaryStatistics, IntSummaryStatistics>(IntSummaryStatistics::new,(r, t) -> r.accept(mapper.applyAsInt(t)),(l, r) -> { l.combine(r); return l; }, CH_ID);
}
- 例子:统计学生的各个年龄信息
@Data
class Student {
private String province;
private int age;
public Student(String province, int age) {
this.age = age;
this.province = province;
}
}
public class Test{
public static void main(String[] args) {
List<Student> students = Arrays.asList(new Student("广东", 23), newStudent("广东", 24), new Student("广东", 23),new Student("北京", 22), new Student("北京", 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());
}
}
十五、 JDK8 新的内存空间和异常处理
- JVM 种类有很多,比如 Oralce-Sun Hotspot, Oralce JRockit, IBM J9, Taobao JVM,我们讲的是Hotspot才有,JRockit以及J9是没有这个区域。
- JVM内存知识 在JDK8之前的HotSpot JVM,有个区域叫做“永久代(permanent generation), 通过在命令行设置参数-XX:MaxPermSize来设定永久代最大可分配的内存空间,如果JDK8⾥⾯设置了PermSize 和MaxPermSize 会被忽略并给出警告。
- 作用:该块内存主要是被JVM⽤来存放 class 和 mate 信息的,当 class 被加载 loader 的时候就会被存储到该内存区中,如方法的编译信息及字节码、常量池和符号解析、类的层级信息,字段,名字等。
- 这个异常应该熟悉 java.lang.OutOfMemoryError: PermGen space,原因是: 永久代空间不够,类太多导致
- jdk8的修改 JDK8 HotSpot JVM 使用本地内存来存储类元数据信息,叫做 元空间(Metaspace),在默认情况下Metaspace的大小只与本地内存大小有关。
- 常用的两个参数 -XX:MetaspaceSize=N 指Metaspace扩容时触发FullGC的初始化阈值-XX:MaxMetaspaceSize=N 指用于限制Metaspace增长的上限,防止因为某些情况导致Metaspace无限的使用本地内存。
- 不管两个参数如何设置,都会从20.8M开始,然后随着类加载越来越多不断扩容调整直到最大。
- 查看大小 jstat -gc pid MC: current metaspace capacity MU: mateaspace utilization 单位是KB。