jdk1.8新特性(2)
自定义函数式接口编程
我们今天再次定义一个函数式接口,加强一个函数式编程思想,直接上代码,根据代码中demo可以很好帮助我们理解函数式编程。
@FunctionalInterface
interface Functions<T,K>{
public K get(T t1,T t2);
}
public class Function {
public static void main(String[] args) {
//定义4个函数
Func<Integer,Integer> add = (a,b)->a+b;
Func<Integer,Integer> Subtraction = (a,b)->a-b;
Func<Integer,Integer> multi = (a,b)->a*b;
Func<Integer,Integer> division = (a,b)->a/b;
System.out.println("加法:"+execute(add,3,3));
System.out.println("减法:"+execute(Subtraction,3,3));
System.out.println("乘法:"+execute(multi,3,3));
System.out.println("除法:"+execute(division,3,3));
}
public static Integer execute(Func<Integer,Integer> func,Integer s1,Integer s2){
//对你定义的函数式逻辑执行,就是执行
// Func<String,String> func = (a,b)->a.toUpperCase() + "-" + b.toUpperCase();
Integer s = func.get(s1, s2);
//可以执行你自己的业务逻辑
//**********************************
//返回
return s;
}
}
结果
加法:6
减法:0
乘法:9
除法:1
JDK8自带函数式接口
Lambda表达式必须先定义接⼝,创建相关⽅法之后才可使⽤,这样做⼗分不便,其实java8已经内置了许多接⼝, 例如下⾯四个功能型接⼝,所以⼀般很少会由⽤户去定义新的函数式接⼝
Java8的最⼤特性就是函数式接⼝,所有标注了@FunctionalInterface注解的接⼝都是函数式接⼝。
函数式接口名字 | 说明 | 方法概述 |
---|---|---|
Consumer< T> | 消费型接⼝:有⼊参,⽆返回值 | void accept(T t); |
Supplier< T> | 供给型接⼝:⽆⼊参,有返回值 | T get() |
Function<T, R> | 函数型接⼝:有⼊参,有返回值 | R apply(T t) |
Predicate< T> | 断⾔型接⼝:有⼊参,有返回值,返回值类型确定是boolean | boolean test(T t) |
consumer
有入参,无返回值
常规调用
package com.example.demo.jdl8;
import org.apache.commons.lang3.StringUtils;
import java.util.function.Consumer;
public class Function2 {
public static void main(String[] args) {
//demo1 方法的函数调用,将入参打印出来,模拟消费了数据
//Consumer<String> consumer = System.out::println;
//上面例子不好理解可以这样写,跟上面逻辑一模一样
Consumer<String> consumer = s->System.out.println(s);
//常规调用
consumer.accept("大步流星");
consumer=s -> {
String s1 = StringUtils.toRootUpperCase(s);
System.out.println(s1);
};
//常规调用
consumer.accept("jack is a good man");
//*******************************************************************************
//函数式调用
System.out.println("函数式调用");
execute(consumer,"jack is a good man");
}
public static <T> void execute(Consumer<T> consumer,T t){
consumer.accept(t);
}
}
结果
大步流星
JACK IS A GOOD MAN
函数式调用
JACK IS A GOOD MAN
集合的foreach函数参数就是消费函数
function
public class Function2 {
public static void main(String[] args) {
String s1 = "jack is a good man";
// Function<String, String> toRootUpperCase = StringUtils::toRootUpperCase;
Function<String, String> toRootUpperCase = s -> StringUtils.toRootUpperCase(s);
System.out.println(execute(toRootUpperCase, s1));
}
public static <T> T execute(Function<T,T> function, T t){
return function.apply(t);
}
}
BiFunction传两个参数一个返回值
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u);
}
demo
public class Function2 {
public static void main(String[] args) {
BiFunction<Integer,Integer,Integer> add = (a,b)->a+b;
BiFunction<Integer,Integer,Integer> Subtraction = (a,b)->a-b;
BiFunction<Integer,Integer,Integer> multi = (a,b)->a*b;
BiFunction<Integer,Integer,Integer> division = (a,b)->a/b;
System.out.println(execute(add,3,3));
System.out.println(execute(Subtraction,3,3));
System.out.println(execute(multi,3,3));
System.out.println(execute(division,3,3));
}
public static <T> T execute(BiFunction<T,T,T> function, T t,T t1){
return function.apply(t,t1);
}
}
Supplier
提供者函数
public static void main(String[] args) {
Supplier<String> supplier = ()->"jack is good man";
String execute = execute(supplier);
System.out.println(execute);
}
public static <T> T execute(Supplier<T> function){
return function.get();
}
Predicate
断言
public class Function2 {
public static void main(String[] args) {
//断言型接口用于集合的过滤
Predicate<String> predicate = a->a.length()>3;
System.out.println(filter(predicate,Lists.newArrayList("aaaa","b","ccc","ddddd")));
}
public static <T> List<T> filter(Predicate<T> predicate,List<T> list) {
List<T> results = new ArrayList<>();
for (T str : list) {
if (predicate.test(str)) {
results.add(str);
}
}
return results;
}
}
方法的函数调用
我们之前调用方法都是对象名.方法名或者类名.方法名。现在如果将方法函数式调用需要使用::,返回最终是一个函数式对象。
public class Function2 {
public static void main(String[] args) {
System.out.println("************************构造方法demo开始*****************");
//调用无参的构造方法,无入参无返回值
Supplier<Clazz> loader = Clazz::new;
Clazz clazz = loader.get();
System.out.println("利用函数式接口无参构造方法创建的对象:"+ JSON.toJSONString(clazz));
System.out.println("*****************************************");
//构造函数参数不同,取决于function的引用,new方法永远有一个默认的返回值,就是这个对象
//所以档没有参数是就是一个Supplier生产者,只有返回值没有参数
//如果有一个参数,就是function,一个参数一个返回值,返回值永远是类对象
Function<String, Clazz> stringClazzCacheLoader = Clazz::new;
Clazz apply = stringClazzCacheLoader.apply("张三");
System.out.println("利用函数式接口一个参构造方法创建的对象:"+JSON.toJSONString(apply));
//两个参数的构造方法返回值就是bifunction,一次类推
//如果jdk自带的函数式接口不满足要求,可以自定义函数式接口
BiFunction<String, Integer, Clazz> bi = Clazz::new;
Clazz clazz1 = bi.apply("张三", 22);
System.out.println("利用函数式接口两个参构造方法创建的对象:"+JSON.toJSONString(clazz1));
System.out.println("************************构造方法demo结束*****************");
System.out.println("************************静态方法demo开始*****************");
//getStatic没有参数 只有一个返回值,所有函数式接口为Supplier,一次类推
Supplier<String> getStatic = Clazz::getStatic;
System.out.println("函数式调用静态方法,返回值类型取决于参数与返回值:"+getStatic.get());
System.out.println("************************静态方法demo结束*****************");
System.out.println("************************实例方法demo开始*****************");
//调用实例方法有两种,一种是根据实例调用 一种是根据类调用 根据类调用默认第一个参数为实例(这个是默认的 必须传值)
//Clazz clazz2 = Clazz.class.newInstance();
Clazz clazz2 = new Clazz("李四",22);
//getName方法,没有入参 有返回值 生产者对象,也就是Supplier函数
//第一种调用方方式 实例::方法名
Supplier<String> getName = clazz2::getName;
String name = getName.get();
System.out.println("实例::方法名 调用:"+name);//李四
//第二种调用方式 类型::实例方法 默认必须有一个参数 第一个参数必须为实例
Function<Clazz, String> getName1 = Clazz::getName;
String apply1 = getName1.apply(clazz2);
System.out.println("类型::实例方法(默认必须有一个参数 第一个参数必须为实例) 调用:"+apply1);//李四
System.out.println("************************实例方法demo结束*****************");
}
}
class Clazz{
private String name;
private Integer age;
public Clazz() {
}
public Clazz(String name) {
this.name = name;
}
public static String getStatic(){
return "空空如也";
}
public Clazz getObject(){
return this;
}
public String getName() {
return name;
}
public Clazz(String name, Integer age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
结果
************************构造方法demo开始*****************
利用函数式接口无参构造方法创建的对象:{"object":{"$ref":"@"}}
*****************************************
利用函数式接口一个参构造方法创建的对象:{"name":"张三","object":{"$ref":"@"}}
利用函数式接口两个参构造方法创建的对象:{"age":22,"name":"张三","object":{"$ref":"@"}}
************************构造方法demo结束*****************
************************静态方法demo开始*****************
函数式调用静态方法,返回值类型取决于参数与返回值:空空如也
************************静态方法demo结束*****************
************************实例方法demo开始*****************
实例::方法名 调用:李四
类型::实例方法(默认必须有一个参数 第一个参数必须为实例) 调用:李四
************************实例方法demo结束*****************
集合操作Stream
如图
数据元素:原始集合,如List、Set、Map等
生成流:可以是串⾏流stream() 或者并⾏流 parallelStream()
中间操作:可以是 排序,聚合,过滤,转换等
终端操作,很多流操作本身就会返回⼀个流,所以多个操作可以直接连接起来,最后统⼀进⾏收集
中间操作(map、filter、sort、limit、allMatch、anyMatch、max、min、reduce等函数)并行流parallelStream
详见下面代码demo
/*****************map函数************************/
System.out.println("--------------map start------------------------------------");
List<String> strings = Lists.newArrayList("1", "2", "3", "4");
//map 函数 对集合进行置换
//例如将某个集合中的vo对象置换为pojo对象,类似与js的map函数
//接受的是一个function函数
List<Integer> collect = strings.stream().map(Integer::parseInt).collect(Collectors.toList());
//同上 List<Integer> collect = strings.stream().map(s->Integer.parseInt(s)).collect(Collectors.toList());
System.out.println("map 转换,字符换转integer :"+collect);
System.out.println("--------------map end------------------------------------");
System.out.println();
System.out.println("--------------filter start------------------------------------");
/*****************filter函数************************/
List<String> strings1 = Lists.newArrayList("啦啦小魔仙", "小施主", "段水流", "王","",null,"a");
//filter 接受的是一个断言函数,返回值为boolean
List<String> collect1 = strings1.stream().filter(StringUtils::isNoneBlank).collect(Collectors.toList());
System.out.println("filter去空:"+collect1);
//取到字符串长度大于3的数据
List<String> collect2 = strings1.stream().filter(s -> StringUtils.length(s) > 3).collect(Collectors.toList());
System.out.println("filter获取字符长度大于3:"+collect2);
System.out.println("--------------filter start------------------------------------");
System.out.println();
System.out.println("--------------sort start------------------------------------");
List<String> collect3 = collect1.stream().sorted().collect(Collectors.toList());
System.out.println("默认自然顺序排序,类需要实现Comparable接口:"+collect3);
//自定义排序规则 自定义Comparator,实现方法
List<String> collect4 = collect1.stream().sorted((a, b) -> b.length() - a.length()).collect(Collectors.toList());
System.out.println("自定义排序规则,按照长度进行排序:"+collect4);
//传递 Comparator.comparing ,传递一个function 按照集合中对象的哪个属性排序
List<String> collect5 = collect1.stream().sorted(Comparator.comparing(a -> a.length())).collect(Collectors.toList());
System.out.println("自定义排序规则,按照长度进行排序:"+collect5);
//反转排序
List<String> collect6 = collect1.stream().sorted(Comparator.comparing(a -> a.length(), Comparator.reverseOrder())).collect(Collectors.toList());
//String::length 方法的函数调用,返回值正好是一个function函数接口
List<String> collect7 = collect1.stream().sorted(Comparator.comparing(String::length).reversed()).collect(Collectors.toList());
System.out.println("自定义排序规则,按照长度进行排序(倒叙):"+collect6);
System.out.println("自定义排序规则,按照长度进行排序(倒叙):"+collect7);
//对集合中对象进行连续排序,先按照班级排序 再按照年龄排序
class Study{
Integer grade;
Integer age;
String name;
public Study(Integer grade, Integer age, String name) {
this.grade = grade;
this.age = age;
this.name = name;
}
public Integer getGrade() {
return grade;
}
public void setGrade(Integer grade) {
this.grade = grade;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
List<Study> studies = Lists.newArrayList(
new Study(10, 8, "周"),
new Study(11, 9, "赵"),
new Study(11, 7, "李"),
new Study(10, 9, "王"),
new Study(11, 8, "薛"));
//先按照班级排序 再按照年龄排序 先排序字段再后面
List<Study> collect8 = studies.stream().sorted(Comparator.comparing(a -> a.age))
.sorted(Comparator.comparing(a -> a.grade)).collect(Collectors.toList());
System.out.println("先按照班级排序 再按照年龄排序 :"+JSON.toJSONString(collect8));
//先按照班级倒叙排序 再按照年龄倒叙排序
List<Study> collect9 = studies.stream().sorted(Comparator.comparing(Study::getAge,Comparator.reverseOrder()))
.sorted(Comparator.comparing(Study::getGrade).reversed()).collect(Collectors.toList());
System.out.println("先按照班级倒叙排序 再按照年龄倒叙排序:"+JSON.toJSONString(collect9));
System.out.println("--------------sort end------------------------------------");
System.out.println("--------------limit start------------------------------------");
List<String> list = Lists.newArrayList("java", "python", "javascript", "golang", "c++", "c");
List<String> collect10 = list.stream().limit(1).collect(Collectors.toList());
System.out.println("阶段流"+collect10);
System.out.println("--------------limit end------------------------------------");
System.out.println("--------------allMatch anyMatch start------------------------------------");
List<String> list2 = Lists.newArrayList("java", "python", "javascript", "golang", "c++", "c");
//allMatch 检查集合所有元素,都符合返回true
boolean b = list2.stream().allMatch(StringUtils::isNoneBlank);
System.out.println("集合所有元素是否都不为空:"+b);
boolean b1 = list2.stream().allMatch(s -> s.length() > 3);
System.out.println("集合所有元素长度是否都大于3:"+b1);
//allMatch 检查集合所有元素,只要有一项符合返回true
boolean b2 = list2.stream().anyMatch(s -> s.length() > 9);
System.out.println("集合有元素长度都大于9:"+b2);
System.out.println("--------------allMatch anyMatch end------------------------------------");
System.out.println("--------------max min start------------------------------------");
System.out.println("原始集合:"+studies);
// Optional<Study> max = studies.stream().max((a, c) -> a.getGrade() - c.getGrade());
Optional<Study> max = studies.stream().max((a, c) -> Integer.compare(a.getGrade(), c.getGrade()));
Study study = max.isPresent() ? max.get() : null;
System.out.println("最大班级是:"+study.getGrade());
Optional<Study> min = studies.stream().min((a, c) -> a.getGrade() - c.getGrade());
Study study1 = min.isPresent() ? min.get() : null;
System.out.println("最小班级是:"+study1.getGrade());
System.out.println("--------------max min end------------------------------------");
System.out.println("--------------并⾏流parallelStream start------------------------------------");
// 线程池(ForkJoinPool)维护⼀个线程队列
// 可以分割任务,将⽗任务拆分成⼦任务,完全贴合分治思想
// 多数情况下并⾏⽐串⾏快
// 部分情况会有线程安全问题,parallelStream⾥⾯使⽤的外部变量
List<String> arrayList = Lists.newArrayList("a", "b", "c", "d", "e");
arrayList.parallelStream().forEach(System.out::println);
System.out.println("--------------并⾏流parallelStream end------------------------------------");
System.out.println("--------------reduce start------------------------------------");
// 根据⼀定的规则将Stream中的元素进⾏计算后返回⼀个唯⼀的值
List<Integer> stringArrayList = Lists.newArrayList(1, 2, 3, 4, 5);
stringArrayList.stream().forEach(System.out::println);
Optional<Integer> reduce = stringArrayList.stream().reduce((a, c) -> a + c);
Integer integer = reduce.isPresent() ? reduce.get() : 0;
System.out.println("集合的合计:"+integer);
Integer reduce1 = stringArrayList.stream().reduce(10, (a, c) -> a + c);
System.out.println("增加初始值10集合的合计:"+reduce1);
Optional<Integer> reduce2 = stringArrayList.stream().reduce((a, c) -> a > c ? a : c);
System.out.println("集合的最大值:"+(reduce2.isPresent()?reduce2.get():0));
System.out.println("--------------reduce end------------------------------------");
collector收集器
Collectors.toList()
Collectors.toMap()
Collectors.toSet()
Collectors.toCollection()
Collectors.toCollection(LinkedList::new)
Collectors.toCollection(CopyOnWriteArrayList::new)
Collectors.toCollection(TreeSet::new)
joining、partitioningBy分组、group by分组、summarizingInt(集合计算)
System.out.println("--------------collector收集器 start------------------------------------");
// Collectors.toList()
// Collectors.toMap()
// Collectors.toSet()
// Collectors.toCollection()
// Collectors.toCollection(LinkedList::new)
// Collectors.toCollection(CopyOnWriteArrayList::new)
// Collectors.toCollection(TreeSet::new)
System.out.println("--------------collector收集器 end------------------------------------");
System.out.println("--------------joining start------------------------------------");
List<String> arrayList1 = Lists.newArrayList("a", "b", "c", "d", "e");
String collect11 = arrayList1.stream().collect(Collectors.joining());
System.out.println("集合转字符串,没有任何分割符:"+collect11);
String collect12 = arrayList1.stream().collect(Collectors.joining(","));
System.out.println("集合转字符串,有分割符:"+collect12);
String collect13 = arrayList1.stream().collect(Collectors.joining(",","[","]"));
System.out.println("集合转字符串,有分割符并增加前缀与后缀:"+collect13);
System.out.println("--------------joining end------------------------------------");
System.out.println("--------------partitioningBy分组 group by分组 start------------------------------------");
//partitioningBy分组 key是boolean类型 value:此对象的集合类型
List<Study> studyList = Lists.newArrayList(
new Study(10, 8, "周"),
new Study(11, 9, "赵"),
new Study(11, 7, "李"),
new Study(10, 9, "王"),
new Study(11, 8, "薛"));
//班级大于10小于10的数据
Map<Boolean, List<Study>> listMap = studyList.stream().collect(Collectors.partitioningBy(s -> s.getGrade() > 10));
listMap.entrySet().forEach(s->{
System.out.println("key:"+s.getKey() + ".value:"+JSON.toJSONString(s.getValue()));
});
System.out.println();
//按年龄分组
Map<Integer, List<Study>> map = studyList.parallelStream().collect(Collectors.groupingBy(s -> s.getAge()));
map.entrySet().forEach(s->{
System.out.println("key:"+s.getKey() + ".value:"+JSON.toJSONString(s.getValue()));
});
System.out.println("--------------collector收集器 end------------------------------------");
System.out.println();
//分组后统计个数
// Map<Integer, Long> collect14 = studyList.stream().collect(Collectors.groupingBy(s -> s.getAge(), Collectors.counting()));
Map<Integer, Long> collect14 = studyList.stream().collect(Collectors.groupingBy(Study::getAge, Collectors.counting()));
collect14.forEach((key,value)->{
System.out.println("key:"+key + "。value:"+value);
});
// summarizing
IntSummaryStatistics collect15 = studyList.stream().collect(Collectors.summarizingInt(s -> s.getAge()));
System.out.println("平均值:" + collect15.getAverage());
System.out.println("⼈数:" + collect15.getCount());
System.out.println("最⼤值:" + collect15.getMax());
System.out.println("最⼩值:" + collect15.getMin());
System.out.println("总和:" + collect15.getSum());
//还可以这样计算,平均年龄,summarizingInt这个函数求
Double collect16 = studyList.stream().collect(Collectors.averagingInt(s -> s.getAge()));
// Double collect16 = studyList.stream().collect(Collectors.averagingInt(Study::getAge));
System.out.println("平均年龄:"+collect16);
Integer collect17 = studyList.stream().collect(Collectors.summingInt(s -> s.getAge()));
System.out.println("总年龄:"+collect17);
分组包括了将list集合转为map的结构,key为同一组相同的数据,value为相同key的数据,是一个集合。如果list转map怎么转呢,就是value不是一个集合,二是一个对象,只是把key提取出来了
public class Test {
public static void main(String[] args) {
Study zhangsan = new Study(1,1, 10, "张三");
Study lisi = new Study(2,1, 10, "李四");
Study wangwu = new Study(3,2, 11, "王五");
Study zhaoliu = new Study(4,2, 11, "赵六");
//一个list集合
List<Study> studies = Lists.newArrayList(zhangsan, lisi, wangwu, zhaoliu);
//转为map key为id,id唯一,此时这么做不会报错
// Map<Long, Study> longStudyMap = Optional.ofNullable(studies)
// .map(a -> a.stream().collect(Collectors.toMap(Study::getId, b -> b))).orElse(new HashMap<>());
Map<Long, Study> longStudyMap = Optional.ofNullable(studies)
.map(a -> a.stream().collect(Collectors.toMap(Study::getId, Function.identity()))).orElse(new HashMap<>());
System.out.println(longStudyMap);
//result
//{1=Test.Study(id=1, grade=1, age=10, name=张三), 2=Test.Study(id=2, grade=1, age=10, name=李四),
// 3=Test.Study(id=3, grade=2, age=11, name=王五), 4=Test.Study(id=4, grade=2, age=11, name=null)}
//value是名字,有一个为null会报错
try {
Map<Long, String> longStudyMap2 = Optional.ofNullable(studies)
.map(a -> a.stream().collect(Collectors.toMap(Study::getId, Study::getName))).orElse(new HashMap<>());
System.out.println(longStudyMap2);
//result java.lang.NullPointerException
} catch (Exception e) {
e.printStackTrace();
}
//处理value为null问题
Map<Long, String> longStudyMap2 = Optional.ofNullable(studies)
.map(a -> a.stream().collect(Collectors.toMap(Study::getId, s->
Optional.ofNullable(s).map(Study::getName).orElse("此名字是空")
))).orElse(new HashMap<>());
System.out.println(longStudyMap2);
//{1=张三, 2=李四, 3=王五, 4=moren}
//转为map key为grade,grade不唯一,用上面的方法会报错
//根据业务不同有不同的处理方式
//后面覆盖前面
Map<Integer, Study> one = Optional.ofNullable(studies).filter(s -> !s.isEmpty())
.map(a -> a.stream().collect(Collectors.toMap(Study::getGrade, Function.identity(), (key1, key2) -> key2))).orElse(new HashMap<>());
System.out.println(one);
//{1=Test.Study(id=2, grade=1, age=10, name=李四), 2=Test.Study(id=4, grade=2, age=11, name=null)}
//value 拼接起来
Map<Integer, String> two = Optional.ofNullable(studies).filter(s -> !s.isEmpty())
.map(a -> a.stream().collect(Collectors.toMap(Study::getGrade,Study::getName, (key1, key2) -> key1 +","+ key2))).orElse(new HashMap<>());
System.out.println(two);
//{1=张三,李四, 2=王五,赵六}
//value 组成集合 同group by
Map<Integer, List<String>> three = Optional.ofNullable(studies).filter(s -> !s.isEmpty())
.map(a->{
return a.stream().collect(Collectors.toMap(Study::getGrade, b -> {
List<String> getNameList = new ArrayList<>();
getNameList.add(b.getName());
return getNameList;
}, (List<String> value1, List<String> value2) -> {
value1.addAll(value2);
return value1;
}));
}).orElseGet(HashMap::new);
System.out.println(three);
//{1=[张三, 李四], 2=[王五, 赵六]}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
static class Study{
long id;
Integer grade;
Integer age;
String name;
}
}
利用jdk8维护一个父子结构关系的对象。
public static void main(String[] args) {
People grandfather = People.builder().id(1).parentId(0).name("爷爷").build();
People father = People.builder().id(2).parentId(1).name("爸爸").build();
People uncle = People.builder().id(3).parentId(1).name("叔叔").build();
People uncle_old = People.builder().id(4).parentId(1).name("大伯").build();
People sister_one = People.builder().id(5).parentId(3).name("堂姐").build();
People sister_two = People.builder().id(6).parentId(4).name("堂哥").build();
People my = People.builder().id(7).parentId(2).name("自己").build();
People mySon = People.builder().id(8).parentId(7).name("我儿子").build();
List<People> people = Lists.newArrayList(grandfather, father, uncle, uncle_old, sister_one, sister_two, my, mySon);
HashMap<String, Long> map = Maps.newHashMap();
generate(grandfather,people,map);
JSONObject jsonObject = new JSONObject(grandfather);
System.out.println( jsonObject.toString());
}
private static void generate(People parent, List<People> people, HashMap<String, Long> map) {
List<People> childList = Lists.newArrayList();
Optional.ofNullable(people).filter(a->!a.isEmpty()).ifPresent(a->{
a.stream()
.filter(b->!map.containsKey(String.valueOf(b.getId())))
.filter(b->b.getParentId() == parent.getId())
.forEach(b->{
map.put(String.valueOf(b.getId()),b.getParentId());
generate(b,people,map);
childList.add(b);
});
});
parent.setChildrenList(childList);
Optional.ofNullable(childList).filter(a->!a.isEmpty()).ifPresent(a->parent.setParent(true));
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
static class People{
long id;
long parentId;
String name;
List<People> childrenList;
boolean isParent;
}
{
"isParent":true,
"name":"爷爷",
"id":1,
"childrenList":[
{
"isParent":true,
"name":"爸爸",
"id":2,
"childrenList":[
{
"isParent":true,
"name":"自己",
"id":7,
"childrenList":[
{
"isParent":false,
"name":"我儿子",
"id":8,
"childrenList":[
],
"parentId":7
}
],
"parentId":2
}
],
"parentId":1
},
{
"isParent":true,
"name":"叔叔",
"id":3,
"childrenList":[
{
"isParent":false,
"name":"堂姐",
"id":5,
"childrenList":[
],
"parentId":3
}
],
"parentId":1
},
{
"isParent":true,
"name":"大伯",
"id":4,
"childrenList":[
{
"isParent":false,
"name":"堂哥",
"id":6,
"childrenList":[
],
"parentId":4
}
],
"parentId":1
}
],
"parentId":0
}
新内存空间Matespace
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
新特性之try-with-resources
private static void test(String filepath){
try(OutputStream out = new FileOutputStream(filepath);) {
out.write((filepath+"XXXXXXXXXXXXXXXXX").getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}