首页 > 其他分享 >JDK8的新特性总结

JDK8的新特性总结

时间:2023-01-18 15:04:48浏览次数:50  
标签:总结 String System 特性 JDK8 println new public out

文章目录


JDK安装

  • win64位-JDK1.8下载||https://pan.baidu.com/s/1fMNaZ0JgySo2MzBT90T5Tw ||jjw3
  • Linux64位-JDK1.8||https://pan.baidu.com/s/1CDpW-UNYyje-p0BxaNtncQ ||nwyd
  • Mac-JDK1.8下载||https://pan.baidu.com/s/1liT9kSLicpXEAd7AdA0nOg ||5bpk

1.接口默认方法实现

  • 在jdk1.8以前接⼝⾥⾯是只能有抽象⽅法,不能有任何⽅法的实现的
  • jdk1.8⾥⾯打破了这个规定,引⼊了新的关键字default,使⽤default修饰⽅法,可以在接⼝⾥⾯定义具体的⽅法实现
  • 默认⽅法: 接⼝⾥⾯定义⼀个默认⽅法,这个接⼝的实现类实现了这个接⼝之后,不⽤管这个default修饰的⽅法就可以直接调⽤,即接⼝⽅法的默认实现

(1)编写接口

public interface Animal {

    void run();

    void eat();

    /**
     * 接口的默认方法
     */
    default void sleep(){
        System.out.println("睡觉");
    }

    /**
     * 静态方法
     */
    static void st(){
        System.out.println("静态方法");
    }
}

(2)编写实现类

public class Dog implements Animal{
    @Override
    public void run() {
        System.out.println("小狗跑");
    }

    @Override
    public void eat() {
        System.out.println("小狗吃");
    }

    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.run();
        dog.eat();
        //直接能掉接口的默认实现
        dog.sleep();
        //直接调用静态方法
        Animal.st();
    }
}

(3)运行结果

JDK8的新特性总结_函数式编程

2.新增Base64加解密API

2.1.Base64编码简介

Base64是网络上常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法,基于64个字符A-Z、0-9、a-z、+、/的编码方式,是一种能将任意二级制数据用64种字节组合成字符串的方法,而这个二进制数据和字符串资料之间是可以相互转换的,实际应用上,Base64不但可以将二进制数据可视化,还可以用于数据传输的加密

2.2.JDK1.8之前Base64的API

  • 早期使用JDK里sun.misc套件下的BASE64Encoder和BASE64Decoder这两个类

(1)编码实战

    public static void main(String[] args) {
        
        //目标字符串
        String str = "lixiang";
        
        //加密
        BASE64Encoder encoder = new BASE64Encoder();
        String strEncode = encoder.encode(str.getBytes("UTF-8"));
        System.out.print("加密后:"+strEncode);
        
        //解密
        BASE64Decoder decoder = new BASE64Decoder();
        String strDecode = new String(decoder.decodeBuffer(strEncode),"UTF-8");
        System.out.print("解密后:"+strDecode);
    }

(2)运行结果

JDK8的新特性总结_函数式编程_02

  • 缺点:编码和解码的效率比较差,公开信息说以后要取消这个方法
  • Apache Commons Codec有提供Base64的编码与解码,但是需要引第三方依赖

2.3.JDK1.8之后Base64的API

  • JDK1.8之后java.util中提供了Base64的类

(1)编码实战

    public static void main(String[] args) {
        
        //目标字符串
        String str = "lixiang";
        
        //加密
        Base64.Encoder encoder = Base64.getEncoder();
        String strEncode = encoder.encodeToString(str);
        System.out.print("加密后:"+strEncode);
        //解密
        Base64.Decoder decoder = Base64.getDecoder();
        String strDecoder = new String(decoder.decode(strEncode),"UTF-8");
        System.out.print("解密后:"+strDecoder); 
    }

(2)运行结果

JDK8的新特性总结_当前日期_03

  • 优点:不需要引包,效率远大于un.misc 和 Apache Commons Codec

3.时间日期处理类

  • 时间处理JDK1.8之前用的是SimpleDateFormat,Calendar等类,缺点是java.util.Date是线程不安全的,而且日期/时间对象比较,加减麻烦
  • JDK1.8新发布Date-Time API进行加强对日期时间的处理
  • 包所在位置:java.time
  • 核心类
LocalDate:不包含具体时间的日期
LocalTime:不包含日期的时间
LocalDateTime:包含了日期及时间

3.1.LocalDate常用的API

LocalDate today = LocalDate.now();

获取当前日期的年份:today.getYear()

获取当前日期的月份:today.getMonth()

获取当前日期的月份(数字):today.getMonthValue()

获取当前日期是当月的多少号:today.getDayOfMonth()

获取当前日期是这一周的周几:today.getDayOfWeek();

获取当前日期+1年,必须返回新的对象才会+1:today.plusYears(1)

获取当前日期+1月,必须返回新的对象才会+1:today.plusMonths(1)

获取当前日期+1周,必须返回新的对象才会+1:today.plusWeeks(1)

获取当前日期+1天,必须返回新的对象才会+1:today.plusDays(1)

获取当前日期-1天,必须返回新的对象才会-1:today.minusDays(1)

获取当前日期-1周,必须返回新的对象才会-1:today.minusWeeks(1)

获取当前日期-1年,必须返回新的对象才会-1:today.minusYears(1)

获取当前日期-1月,必须返回新的对象才会-1:today.minusMonths(1)

日期比较,当前日期与目标日期之后:date.isAfter(today)

日期比较,当前日期与目标日期之前:date.isBefore(today)

修改当前日期的年份:today.withYear(1999)

修改当前日期的月份:today.withMonth(3)

修改当前对象在当月的日期:today.withDayOfMonth(5)

比较两个日期是否相等:date.isEqual(today)

3.2.日期格式化

  • JDK1.8之前:SimpleDateFormat来进行格式化,但SimpleDateFormat并不是线程安全的
  • JDK1.8之后:引入线程安全的日期与时间DateTimeFormatter
//获取当前时间
LocalDateTime today = LocalDateTime.now();
System.out.println("today:"+today);

//日期格式化
LocalDateTime today = LocalDateTime.now();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String date = dtf.format(today);

JDK8的新特性总结_当前日期_04

//定制日期对象,参数分别对应,年、月、日、时、分、秒
LocalDateTime localDateTime = LocalDateTime.of(2021,11,12,8,10,2);

JDK8的新特性总结_System_05

3.3.日期的比较

LocalDateTime date1 = LocalDateTime.of(2021,11,12,8,10,2);
LocalDateTime date2 = LocalDateTime.of(2020,11,12,8,10,2);

Duration duration = Duration.between(date1,date2);
//两个时间差的天数
System.out.println(duration.toDays());
//两个时间的小时差
System.out.println(duration.toHours());
//两个时间的分钟差
System.out.println(duration.toMinutes());
//两个时间的毫秒差
System.out.println(duration.toMillis());
//两个时间的纳秒差
System.out.println(duration.toNanos());

JDK8的新特性总结_System_06

4.空指针处理Optional类

(1)Optional类的用处

主要解决的问题是空指针异常(NullPointerException)

(2)创建Optional类

  • of
    • null值作为参数传进去会报异常
    • Optional optional = Optional.of(空对象);

JDK8的新特性总结_java_07

  • ofNullable
    • null值作为参数传进去不会报异常
    • Optional optional = Optional.ofNullable(空对象);

JDK8的新特性总结_函数式编程_08

(3)访问Optional对象的值

  • get
    • 获取Optional对象中的值
    • optional.get()
  • isPresent
    • 判断optional是否存在,如果不存在返回false,一般在获取Optional对象中的值之前调用判断
    • optional.isPresent()
Student student = null;

//Optional<Student> optional = Optional.of(student);

Optional<Student> optional = Optional.ofNullable(student);

//拿值之前先判断optional是否为空
if(optional.isPresent()){
     Student student1 = optional.get();
}else{
     System.out.println("optional中值为空");
}

JDK8的新特性总结_开发语言_09

(4)兜底orElse方法

  • orElse()如果有只就返回该值,否则就传送一个默认值
Student student1 = null;
Student student2 = new Student("李祥",20);

//当student1为空时,就返回student2对象,不为空就返回student1对象
Student orElse = Optional.ofNullable(student1).orElse(student2);

System.out.println(orElse);

JDK8的新特性总结_System_10

//判断对象年龄如果为空值就传送一个默认7
Optional.ofNullable(student1).map(obj->obj.getAge()).orElse(7);
System.out.println("age:"+integer);

JDK8的新特性总结_System_11

5.Lambda表达式

(1)什么是Lambda表达式

  • 在JDK8之前,java是不支持函数式编程的,所谓函数编程,可以理解成将一个函数(行为动作)作为一个方法的参数传递过去执行,面向对象编程是对数据的抽象,而函数式编程是对行为的抽象

(2)JDk8之前创建线程的方式与Lambda创建线程的方式

  • JDK8之前创建线程
public static void main(String[] args) {

    new Thread(new Runable(){
        @Override
        public void run(){
            System.out.print("测试");
        }
    }).start();

}
  • Lambda表达式创建线程
public static void main(String[] args) {
	
    //new Thread(()->{System.out.print("测试");}).start();
    new Thread(()->System.out.print("测试")).start();
}

(3)集合容器元素排序

  • JDK8之前集合排序
public static void main(String[] args) {
	Arrays.asList("aaa","bbb","ccc","fff","ddd");
    Collections.sort(list,new Comparator<String>(){
        @Override
        public int compare(String a,String b){
            return a.compareTo(b);
        }
    });
}
  • Lambda表达式方式排序
public static void main(String[] args) {
	Arrays.asList("aaa","bbb","ccc","fff","ddd");
    Collections.sort(list,(x,y) -> x.comparaTo(y));
}

(4)Lambda表达式的使用场景

一个接口中只包含一个需要实现的方法,可以使用Lambda表达式,这样的接口称为函数式接口,语法:(params) -> expression
(x,y) -> {System.out.print(x+y);}

(x,y):这一部分为参数,当只有一个参数时可以省略括号,x->,当没有参数时,直接写括号()

->:表示指向执行的方法体

{System.out.print(x+y);}:表示执行的方法体,可以是表法式,也可以是代码块,当是表达式的时候可以省略{},没有{}时;不要写,代码块时要加上{},就和平常的语句逻辑一样。

好处:Lambda表达式的实现方式时在本质以匿名内部类的方式进行实现,减少代码冗余,提高开发效率。

(5)自定义Lambda接口

  • 定义一个函数接口,需要加上@FuncationInterface注解,只允许有一个默认的方法实现。

  • 定义一个可以使用加减乘除的接口,之前需要定义四个方法,现在只需一个方法

  • 编写接口,定义方法,加上FunctionInterface注解

@FunctionInterface
public interface OperFunction<R,T>{
    R operator(T t1,T t2);
}

JDK8的新特性总结_函数式编程_12

  • 定义方法,将接口作为方法入参
public static Integer operator(Integer x,Integer y,OperFunction<Integer,Integer> of){
    return of.operator(x,y);
}

JDK8的新特性总结_System_13

  • 测试
public static void main(String[] args) {
    System.out.print(operator(x,y,(x,y)->x+y));
    System.out.print(operator(x,y,(x,y)->x-y));
    System.out.print(operator(x,y,(x,y)->x*y));
    System.out.print(operator(x,y,(x,y)->x/y));
}

JDK8的新特性总结_函数式编程_14

6.函数式编程

6.1.Java8内置的四大函数式接口

  • 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);

6.2.函数式编程Function

  • Function
    • 传入一个值经过函数的计算返回另一个值
    • T:入参类型,R:出参类型
@FunctionalInterface
public interface Function<T, R> {    
    /**     
     * Applies this function to the given argument.     
     * @param t the function argument     
     * @return the function result    
     */    
    R apply(T t);
}
  • 作用:将转换后逻辑提取出来,解耦合
public class FunctionObj implements Function {
    @Override
    public Object apply(Object o) {
        return o+":apply处理";
    }
}
public static void main(String[] args) {
     Object lixiang = apply("lixiang", new FunctionObj());
     System.out.println(lixiang);
}

public static Object apply(String o,FunctionObj obj){
     return obj.apply(o);
}

JDK8的新特性总结_函数式编程_15

6.3.函数式编程BiFunction

  • BiFunction Function只能接受一个参数,如果要传递两个参数,则用BiFunction。
@FunctionalInterface
public interface BiFunction<T,U,R>{
    R apply(T t,U u);
}
public static void main(String[] args) {  
    
    System.out.println(operator(10,21,(a,b)->a+b));   
    
    System.out.println(operator(10,2,(a,b)->a-b)); 
    
    System.out.println(operator(8,4,(a,b)->a*b)); 
    
    System.out.println(operator(10,2,(a,b)->a/b)); 
    
}    
public static Integer operator(Integer a, Integer b, BiFunction<Integer,Integer, Integer> bf) {       
    return bf.apply(a, b);   
}

JDK8的新特性总结_java_16

6.4.函数式编程Consumer

  • Consumer消费型接口:有入参,无返回值
  • 将 T 作为输入,不反回任何内容
    • 调用方法:void accept(T t);
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}
  • 用途:因为没有出参常用于打印,发送短信等消费动作
    public static void main(String[] args) {

        sendMessage("11111111",phone -> System.out.println(phone+"已经被发送"));
    }

    public static void sendMessage(String phone, Consumer<String> consumer){
        consumer.accept(phone);
    }

JDK8的新特性总结_当前日期_17

6.5.函数式编程Supplier

  • Supplier:供给型接口:无入参,有返回值
  • T:出参类型
    • 调用方法:T get();
@FunctionalInterface
public interface Supplier<T> {
    T get();
}
  • 用途:泛型一定和方法的返回值是一种类型,如果需要获得一个数据,并且不需要传入参数,可以使用Supplier接口,例如无参的工厂方法。
    public static void main(String[] args) {

        Student student = newStudent();

        System.out.println(student);

    }
    public static Student newStudent(){
        Supplier<Student> supplier=()-> new Student("lixiang",20);

        return supplier.get();
    }

JDK8的新特性总结_System_18

6.6.函数式编程Predicate

  • Predicate:断言型接口:有入参,有出参,返回值类型是boolean
  • T:入参类型,出餐类型是Boolean
  • 调用方法:boolean test(T t)
@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}  
  • 用途:接收一个参数,用于判断是否满足一定的条件过滤数据
public static void main(String[] args) {

        List<String> list = Arrays.asList("awewrwe","vdssdsd","aoooo","psdddsd");

        List<String> results = filter(list, obj -> obj.startsWith("a"));

        System.out.println(results);
    }

    public static List<String> filter(List<String> list,Predicate<String> predicate){
        List<String> results = new ArrayList<>();

        for (String s : list) {
            if(predicate.test(s)){
                results.add(s);
            }
        }
        return results;
    }

JDK8的新特性总结_当前日期_19

6.7.方法与构造方法引用

  • 以前调用方法:对象.方法名(),类名.方法名()
  • JDK8提供了另外一种方式 :: (双冒号)
方法引用是一种更简洁易懂的lambda表达式,操作符是双冒号::,用来直接访问类或者实例已经存在的方法或者构造方法。

通过语法引用,可以将方法的引用赋值给一个变量

语法:左边是容器(可以是类名,实例名),中间是"::",右边是相应的方法名

静态方法:ClassName::methodName
实例方法:Instance::methodName
构造函数:类名::new

单个参数
Function<入参1,返回类型> func = 方法引用

应用 func.apply(݇入参);

两个参数
BiFunction<݇入参1, 入参2> func = 方法引用
应用 func.apply(入参1,入参2);

测试调用

public static void main(String[] args) {
        //静态方法的调用
        Function<String,Integer> function1 =  Integer::parseInt;
        Integer num = function1.apply("1024");
        System.out.println("转化后:"+num);

        //实例方法的调用
        String context = "lixiang";
        Function<Integer,String> function2 = context::substring;
        String str = function2.apply(1);
        System.out.println("截取后的字符串:"+str);

        //构造方法的调用,双参数
        BiFunction<String,Integer,Student> function3 = Student::new;
        Student lixiang = function3.apply("lixiang", 20);
        System.out.println(lixiang);

        //构造方法的调用,单个参数
        Function<String,Student> function4 = Student::new;
        Student lisi = function4.apply("lisi");
        System.out.println(lisi);

        //函数作为参数传递到另一个方法中
        String sayHello = sayHello(String::toUpperCase, "lixiang");
        System.out.println(sayHello);

    }

    public static String sayHello(Function<String,String> function,String str){
        String apply = function.apply(str);
        return apply;
    }

JDK8的新特性总结_开发语言_20

7.Stream流式操作集合框架

7.1.Stream简介

(1)什么是stream

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

JDK8的新特性总结_System_21

  • 操作详情
    • 数据元素就是原始的集合,List、Map、Set等
    • 生成流,可以是串行流stream()或者并行流parallelStream()
    • 中间操作,可以是排序,聚合,过滤,转换等
    • 终端操作,很多流操作本身就会返回一个流,所以多个操作可以直接连接起来,最后统一收集

(2)案例

        List<String> list = Arrays.asList("SpringBoot", "SpringCloud", "Redis", "RabbitMQ");

        List<String> collect = list.stream().map(obj -> obj + "-拼接").collect(Collectors.toList());

        for (String s : collect) {
            System.out.println(s);
        }

JDK8的新特性总结_开发语言_22

7.2.map和filter函数

(1)map函数

  • 将流中的每一个元素T映射成R(类似类型转换)

  • 应用场景:转换对象,类似DO对象转换成DTO对象

  • map函数源码

JDK8的新特性总结_java_23

  • 测试
    public static void main(String[] args) {
        List<User> users = Arrays.asList(
                new User(1, "小东", "123"),
                new User(2, "小李", "123"),
                new User(3, "小王", "123"),
                new User(4, "小张", "123"));
        List<UserDTO> collect = users.stream().map(user -> {
            UserDTO userDTO = new UserDTO();
            userDTO.setUserId(user.getId());
            userDTO.setUsername(user.getName());
            return userDTO;
        }).collect(Collectors.toList());

        for (UserDTO userDTO : collect) {
            System.out.println(userDTO);
        }
    }

JDK8的新特性总结_开发语言_24

(2)filter函数

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

  • 应用场景:过滤出符合条件的元素

  • filter函数源码

JDK8的新特性总结_当前日期_25

  • 测试
 List<String> list = Arrays.asList("SpringBoot", "SpringCloud", "Redis", "RabbitMQ","JUC");
//filter
List<String> collect5 = list.stream().filter(str -> str.length() > 4).collect(Collectors.toList());
System.out.println(collect5);

JDK8的新特性总结_开发语言_26

7.3.sorted和limit函数

(1)sorted函数

  • sorted()对流进行自然的排序,其中的元素必须实现Comparable接口
  • 应用场景:需要对集合的元素进行定制化排序
  • sorted源码

JDK8的新特性总结_函数式编程_27

  • 测试
//排序,sort(),默认升序
List<String> collect1 = list.stream().sorted().collect(Collectors.toList());
System.out.println("sort()按照英文字母升序:"+collect1);

//根据长度排序,默认升序
List<String> collect2 = list.stream().sorted(Comparator.comparing(obj -> obj.length())).collect(Collectors.toList());
System.out.println("sort()按照英文字母的长度升序:"+collect2);

//根据长度排序,降序
List<String> collect3 = list.stream().sorted(Comparator.comparing(obj -> obj.length(),Comparator.reverseOrder())).collect(Collectors.toList());
System.out.println("sort()按照英文字母的长度降序:"+collect3);

JDK8的新特性总结_System_28

(2)limit函数

  • limit()截断流使其最多包含指定的数量的元素
  • 应用场景:排行榜,截取前多少名
  • limit源码

JDK8的新特性总结_当前日期_29

  • 测试
//根据长度排序,降序,截取前三个
List<String> collect4 = list.stream()
       .sorted(Comparator.comparing(String::length,Comparator.reverseOrder())).limit(3)
       .collect(Collectors.toList());
System.out.println(collect4);

JDK8的新特性总结_当前日期_30

JDK8的新特性总结_当前日期_31

7.4.allMatch和anyMatch函数

(1)allMatch函数

  • 检查是否匹配所有元素,主有全部符合才返回true
  • allMatch源码

JDK8的新特性总结_java_32

  • 测试
List<String> list = Arrays.asList("SpringBoot", "SpringCloud", "Redis", "RabbitMQ","Netty","JUC","Docker");

boolean allFlag = list.stream().allMatch(str -> str.length()>5);

System.out.println("allFlag全部满足返回true:"+allFlag);

JDK8的新特性总结_System_33

(2)anyMatch函数

  • 检查是否匹配所有元素,主有全部符合才返回true
  • anyMatch源码

JDK8的新特性总结_当前日期_34

  • 测试
List<String> list = Arrays.asList("SpringBoot", "SpringCloud", "Redis", "RabbitMQ","Netty","JUC","Docker");

boolean allFlag = list.stream().anyMatch(str -> str.length()>5);

System.out.println("allFlag全部满足返回true:"+allFlag);

JDK8的新特性总结_函数式编程_35

7.4.max和min函数

(1)max函数

  • 获取集合元素中的最大值
  • max源码

JDK8的新特性总结_当前日期_36

  • 测试
Optional<Student> max = list.stream().max(Comparator.comparingInt(Student::getAge));

if (max.isPresent()){
    System.out.println("最大年龄:"+max.get().getAge());
}

JDK8的新特性总结_当前日期_37

(2)min函数

  • 获取集合中的最小值
  • min源码

JDK8的新特性总结_System_38

  • 测试
Optional<Student> min = list.stream().min((student1, student2) -> {
     return Integer.compare(student1.getAge(), student2.getAge());
});

if(min.isPresent()){
     System.out.println("最小年龄:"+min.get().getAge());
}

JDK8的新特性总结_函数式编程_39

7.5.并行流parallelStream

  • 为什么会有这个并行流
    • 集合做重复的操作,如果使用串行执行会相当耗时,因此一般会采用多线程来加快,Java8的paralleStream用fork/join框架提供了并发执行能力
    • 底层原理
      • 线程池(ForkJoinPool)维护一个线程队列
      • 可以分割任务,将父任务拆分成子任务,完全贴合分治思想
  • fork/join框架

JDK8的新特性总结_开发语言_40

  • 两个区别
List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10);

//串行流
System.out.print("串行流:");
numbers.stream().forEach(num -> System.out.print(num+" "));

System.out.println();

//并行流
System.out.print("并行流:");
numbers.parallelStream().forEach(num -> System.out.print(num+" "));

JDK8的新特性总结_System_41

  • 存在问题
  • parallelStream并行是否一定比Sream串行快?
    • 错误,数据量少的情况,可能串行更快,ForkJoin会耗性能
  • 多数情况下并行比串行块,是否可以都用并行
    • 不行,部分情况会线程安全问题,parallelStream里面使用的外部变量,比如集合一定要使用线程安全集合,不然就会引用多线程安全问题
for (int i = 0; i < 10; i++) {
    //List<Integer> list = new ArrayList<>();
    CopyOnWriteArrayList list = new CopyOnWriteArrayList();
    IntStream.range(1,100).parallel().forEach(list::add);
    System.out.println(list.size());
}

JDK8的新特性总结_开发语言_42

7.6.reduce函数

  • 什么是reduce操作
    • 聚合操作,中文意思是“减少”
    • 根据一定的规则将Stream中的元素进行计算后返回一个唯一的值
    • 源码分析

JDK8的新特性总结_开发语言_43

List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);

//将集合内的元素相加
Integer integer = list.stream().reduce((x, y) -> x + y).get();

System.out.println("集合内元素相加:"+integer);

//初始值100,将集合内的元素相加
Integer integer1 = list.stream().reduce(100,(x,y) -> x+y);

System.out.println("100累加集合内的元素:"+integer1);

//判断最大值返回
Integer integer2 = list.stream().reduce((x, y) -> x > y ? x : y).get();

System.out.println("集合内最大元素:"+integer2);

JDK8的新特性总结_System_44

7.7.集合foreach

  • 集合遍历方式
    • for循环
    • 迭代器Iterator
  • 源码分析

JDK8的新特性总结_函数式编程_45

  • JDK8里面的新增接口
List<Student> result = Arrays.asList(new Student(32),new Student(33),new Student(21),new Student(29),new Student(18));
result.forEach(obj -> System.out.println(obj.getAge()));

JDK8的新特性总结_开发语言_46

  • 注意点:
    • 不能修改包含外部的变量的值
    • 不能用break或者return或者continue等关键词结束或者跳出循环

8.Collector收集器和集合统计

8.1.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的作用
    • 提供了很多常见的集合的收集
    • Collectors.toList()
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
    );
}
  • ArrayList::new,创建一个ArrayList作为累加器
  • List::add,对流中的元素直接加到累加器中
  • reduce,对子任务归集结果直接全部添加到前一个子任务结果中
  • CH_ID是一个unmodifableSet集合

常见的收集器

  • Collector.toMaps():创建一个map收集器
  • Collector.toSet():创建一个set收集器
  • Collector.toCollection():自定义收集器
    • Collector.toCollection(LinkedList::new)
    • Collector.toCollection(TreeSet::new)

8.2.joining函数

  • 拼接函数,将集合内的元素按照一定规则拼接起来,Collectors.joining()
//三种重载方法
Collectors.joining() //无参数默认按照空字符拼接
Collectors.joining("-") //一个参数,按照“-”进行分割
Collectors.joining("-","{","}") //三个参数,第一个为分隔符,后两个为前缀后缀
  • 源码

JDK8的新特性总结_当前日期_47
JDK8的新特性总结_java_48
JDK8的新特性总结_当前日期_49

  • 测试
List<String> list = Arrays.asList("SpringBoot","Docker","Java","SpringCloud","Netty");

String collect1 = list.stream().collect(Collectors.joining());

System.out.println(collect1);

String collect2 = list.stream().collect(Collectors.joining("-"));

System.out.println(collect2);

String collect3 = list.stream().collect(Collectors.joining("-", "{", "}"));

System.out.println(collect3);

JDK8的新特性总结_System_50

8.3.partitioningBy分组

  • Collectors.partitioningBy()会根据筛选条件进行分组,返回一个Map<Boolean,List>类型,boolean为true的表示符合条件的,false的为不符合筛选条件的。

  • 源码

JDK8的新特性总结_System_51

  • 测试
List<String> list = Arrays.asList("Java","SpringBoot","HTML5","CSS3");

Map<Boolean, List<String>> collect = list.stream().collect(Collectors.partitioningBy(obj -> obj.length() > 4));

System.out.println(collect);

JDK8的新特性总结_开发语言_52

8.4.groupingBy分组

  • Collectors.groupingBy(),会根据实体Bean的某个属性进行分组,更实用,返回的是Map<String,List>,key为要分组的实体Bean的属性值
  • 源码

JDK8的新特性总结_开发语言_53
JDK8的新特性总结_java_54

  • 测试
List<Student> students = Arrays.asList(
      new Student("lx", 23, "北京"),
      new Student("ls", 24, "天津"),
      new Student("zs", 23, "⼴东"),
      new Student("ww", 22, "⼴东"),
      new Student("ld", 20, "北京"),
      new Student("xs", 20, "⼴东"),
      new Student("ok", 25, "北京"));
Map<String, List<Student>> collect = students.stream().collect(Collectors.groupingBy(obj -> obj.getProvince()));
//第二种方式
//Map<String, List<Student>> collect1 = students.stream().collect(Collectors.groupingBy(Student::getProvince));

        collect.forEach((key,value) -> {
            System.out.println("----"+key);

            value.forEach(obj-> System.out.println(obj));

        });

JDK8的新特性总结_函数式编程_55

8.5.counting函数

  • 用于统计groupingBy于分组之后,每组元素的个数
  • 源码

JDK8的新特性总结_当前日期_56

  • 测试
List<Student> students = Arrays.asList(
       new Student("lx", 23, "北京"),
       new Student("ls", 24, "天津"),
       new Student("zs", 23, "⼴东"),
       new Student("ww", 22, "⼴东"),
       new Student("ld", 20, "北京"),
       new Student("xs", 20, "⼴东"),
       new Student("ok", 25, "北京"));

Map<String, Long> collect1 = students.stream().collect(Collectors.groupingBy(Student::getProvince, Collectors.counting()));

collect1.forEach((key,value) -> {
     System.out.println("---"+key);
     System.out.println("---"+value);
});

JDK8的新特性总结_System_57

8.6.summarizing集合统计

  • 集合相关的统计都能实现,根据实体Bean的某个属性进行统计,求最大值,最小值,总和等等
  • 分类
    • summarizingInt
    • summarizingLong
    • summarizingDouble
  • 测试,统计各个学生的年龄信息
IntSummaryStatistics collect = students.stream().collect(Collectors.summarizingInt(Student::getAge));
System.out.println("平均值:"+collect.getAverage());
System.out.println("总人数:"+collect.getCount());
System.out.println("年龄总和:"+collect.getSum());
System.out.println("最大值:"+collect.getMax());
System.out.println("最小值:"+collect.getMin());

JDK8的新特性总结_java_58

9.Collection和Lambda实战

(1)需求:求两个集合的交集、差集、去重并集,两集合的各自平均值,总和

(2)创建两个集合

//总价 35
List<VideoOrder> videoOrders1 = Arrays.asList( new VideoOrder("20190242812", "springboot教程", 3), new VideoOrder("20194350812", "微服务SpringCloud", 5), new VideoOrder("20190814232", "Redis教程", 9), new VideoOrder("20190523812", "⽹⻚开发教程", 9), new VideoOrder("201932324", "百万并发实战Netty", 9));

//总价 54
List<VideoOrder> videoOrders2 = Arrays.asList( new VideoOrder("2019024285312", "springboot教程", 3), new VideoOrder("2019081453232", "Redis教程", 9), new VideoOrder("20190522338312", "⽹⻚开发教程", 9), new VideoOrder("2019435230812", "Jmeter压⼒测试", 5), new VideoOrder("2019323542411", "Git+Jenkins持续集成", 7), new VideoOrder("2019323542424", "Idea全套教程", 21));

(3)注意一点要重写equals和hashcode方法

@Override
public boolean equals(Object o) {
    if(o instanceof VideoOrder){
        VideoOrder o1 = (VideoOrder)o;
        return this.title.equals(o1.title);
    }
    return super.equals(o);
}

@Override
public int hashCode() {
    return title.hashCode();
}

(4)计算两个集合的交集

List<VideoOrder> clist = videoOrder1.stream().filter(videoOrder2::contains).collect(Collectors.toList());

(5)计算两个集合的差集

List<VideoOrder> nclist = videoOrder1.stream().filter(obj -> !videoOrder2.contains(obj)).collect(Collectors.toList());

(6)计算两个集合的去重并集

List<VideoOrder> allList = videoOrder1.paralleStream().distinct().collect(Collectors.toList());
allList.addAll(videoOrder2);

(7)计算订单价格的平均值

double avg = videoOrder1.stream().collect(Collectors.averagingInt(VideoOrder::getMoney)).doubleValue();

(8)计算订单价格的总和

Integer sum = videoOrders1.stream().collect(Collectors.summingInt(VideoOrder::getMoney));

JDK8的新特性总结_当前日期_59

10.内存空间和异常处理

10.1.新内存空间Matespace

  • JVM 种类有很多,⽐如 Oralce-Sun Hotspot, Oralce JRockit, IBM J9, Taobao JVM,我们讲的是Hotspot才有,JRockit以及J9是没有这个区域
  • JVM内存JDK8之前的HotSpot JVM,有个区域叫做”永久代“(permanent generation),通过在命令行设置参数:-XX:MaxPermSize来设定永久代最大可分配的内存空间
  • 如果JDK8中设置了PermSize和Max PermSize会被忽略并且警告
  • 作用:该块内存主要是被JVM用来存放class和mate信息的,当class被加载loader的时候会被存储到该内存区中,入方法的编译信息及字节码、常量池和符号解析、类的层级信息,字段、名字等
  • java.lang.OutOfMemoryError: PermGen space
    • 异常原因:永久代空间不够,可能类太多导致
  • JDK8使用本地内存存储类元数据信息,叫做元空间(Metaspcae)
  • 在默认情况下Metaspcae的大小至于本地内存大小有关系
  • 常⽤的两个参数
    • -XX:MetaspaceSize=N 指Metaspace扩容时触发FullGC的初始化阈值
    • -XX:MaxMetaspaceSize=N 指⽤于限制Metaspace增⻓的上限,防⽌因为某些情况导致Metaspace⽆限的使⽤本地内存
  • 不管两个参数如何设置,都会从20.8M开始,然后随着类加载越来越多不断扩容调整直到最⼤
  • 查看MetaspaceSize的大小
  • jstat -gc pid

10.2.try-with-resources(JDK7)

  • 自动关流
  • jdk7之前处理异常
    public static void main(String[] args) throws FileNotFoundException {
        String filePath = "F:\\1.txt";
        test(filePath);
    }
    private static void test(String filePath) throws FileNotFoundException {
        OutputStream outputStream = new FileOutputStream(filePath);

        try {
            outputStream.write((filePath+"学习").getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
  • jdk7之后处理异常
    public static void main(String[] args) throws FileNotFoundException {
        String filePath = "F:\\1.txt";
        test(filePath);
    }

    private static void test(String filePath) throws FileNotFoundException {

        //自动关流,当有多个文件时,直接用;分割就可以
        try (OutputStream outputStream = new FileOutputStream(filePath)){
            outputStream.write((filePath + "学习").getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • 实现了AutoCloseable接口的类,在try()里面声明该类实例的时候,try结束后自动i盗用的close方法,这个动作会早于finally里面调用的方法。
  • 不管是否出现异常,try()里面的实例都会被调用close方法。
  • try里面可以声明多个自动关闭的对象,越早声明的对象,会越晚被关掉。
    public static void main(String[] args) throws FileNotFoundException {
        String filePath = "F:\\1.txt";
        test(filePath);
    }
    private static void test(String filePath) throws FileNotFoundException {
        OutputStream outputStream = new FileOutputStream(filePath);

        try {
            outputStream.write((filePath+"学习").getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
  • jdk7之后处理异常
    public static void main(String[] args) throws FileNotFoundException {
        String filePath = "F:\\1.txt";
        test(filePath);
    }

    private static void test(String filePath) throws FileNotFoundException {

        //自动关流,当有多个文件时,直接用;分割就可以
        try (OutputStream outputStream = new FileOutputStream(filePath)){
            outputStream.write((filePath + "学习").getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • 实现了AutoCloseable接口的类,在try()里面声明该类实例的时候,try结束后自动i盗用的close方法,这个动作会早于finally里面调用的方法。
  • 不管是否出现异常,try()里面的实例都会被调用close方法。
  • try里面可以声明多个自动关闭的对象,越早声明的对象,会越晚被关掉。

标签:总结,String,System,特性,JDK8,println,new,public,out
From: https://blog.51cto.com/u_15646271/6019233

相关文章