JDK8新特性

简介

1.速度更快
2.代码更少(Lambda表达式)
3.强大的Stream API
4.便于并行
5.最大化减少空指针异常 Optical

JDK8新特性列表

1.Lambda 表达式
2.函数式接口
3.方法引用与构造器引用
4.Stream API
5.接口中的默认方法与静态方法
6.新时间日期 API
7.其他新特性

1.Lambda 表达式

为什么使用 Lambda 表达式?
Lambda 是一个 匿名函数,我们可以把 Lambda表达式理解为是 一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。

/**
 * 左侧  Lambda 表达式的参数列表
 * 右侧  Lambda 所需执行的功能,即 Lambda 提
 * 语法格式1:无参数 返回值
 *      () -> System.out.println("hello");
 * 语法格式2:有一个参数  有返回值
 *      (t) -> System.out.println(t);
 * 语法格式3:有一个参数 小括号可以省略不写 有返回值
 *      t -> System.out.println(t);
 * 语法格式4:有2个参数 有多条语句
 *          (x, y) -> {
 *             System.out.println("函数式接口");
 *             return x.compareTo(y);
 *         };
 * 语法格式5:有2个参数 只有一条语句 大括号和return可以都省了 如上
 *
 * 语法格式6.参数列表的数据类型可以不写,,因为JVM可以推断类型,如果写,都要写
 */

从匿名类到 Lambda 的转换

public class LambdaTest {
    /**
     * 左侧  Lambda 表达式的参数列表
     * 右侧  Lambda 所需执行的功能,即 Lambda 提
     * 语法格式1:无参数 返回值
     *      () -> System.out.println("hello");
     * 语法格式2:有一个参数  有返回值
     *      (t) -> System.out.println(t);
     * 语法格式3:有一个参数 小括号可以省略不写 有返回值
     *      t -> System.out.println(t);
     * 语法格式4:有2个参数 有多条语句
     *          (x, y) -> {
     *             System.out.println("函数式接口");
     *             return x.compareTo(y);
     *         };
     * 语法格式5:有2个参数 只有一条语句 大括号和return可以都省了 如上
     *
     * 语法格式6.参数列表的数据类型可以不写,,因为JVM可以推断类型,如果写,都要写
     */
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("LambdaTest.run");
            }
        };
        Thread thread1 = new Thread(runnable);
        thread1.start();
        //Lambda 表达式

        Runnable runnable1 = () -> System.out.println("hello");
        Thread thread = new Thread(runnable1);
        thread.start();

        Consumer consumer = t -> System.out.println(t);
        consumer.accept("hello");

        Comparator comparator = (x, y) -> {
            System.out.println("函数式接口");
            return x.compareTo(y);
        };
        Comparator comparator1 = (String x,String y) -> {
            System.out.println("函数式接口");
            return x.compareTo(y);
        };
    }
}
2.函数式接口

什么 是函数式接口
 只包含一个抽象方法的接口,称为 函数式接口。
 你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda
表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方
法上进行声明)。
 我们可以在任意函数式接口上使用 @ FunctionalInterface 注解,
这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包
含一条声明,说明这个接口是一个函数式接口

@FunctionalInterface
public interface MyFun {
    Integer getVal(Integer num);
}
public class LambdaTest3 {
    /**
     * 左侧  Lambda 表达式的参数列表
     * 右侧  Lambda 所需执行的功能,即 Lambda 提
     * 函数式接口:接口中只有一个抽象方法的接口,称为函数式接口 
     * 可以使用  @FunctionalInterface 修饰
     * 就可以检查是不是函数式接口
     */
    public static void main(String[] args) {
        //需求:进行运算
        System.out.println(op(100, (x) -> x * x));

    }

    public static Integer op(Integer num, MyFun myFun) {
        return myFun.getVal(num);
    }
}

作为递 参数传递 Lambda 将 表达式:为了将 Lambda 表达式作为参数传递,接收 Lambda 该 表达式的参数类型必须是与该 Lambda 表达式兼容的函数式接口的类型

JDK8新特性_第1张图片
Java内置接口

实例

public class LambdaTest4 {
    public static void main(String[] args) {
        con(100, (x) -> System.out.println(x * x));

        for (Integer number : getNum(100, () -> (int) (Math.random() * 100))) {
            System.out.println(number);
        }
        System.out.println(strHander("哈斯      ", (str) -> str.trim()));
        List list = new ArrayList<>();
        list.add("234");
        list.add("ger2vsdv34");
        list.add("2bvadfvb34");
        list.add("afb2gb34");
        list.add("awseg234");
        for (String name : fileNames(list,(x)->x.contains("2"))){
            System.out.println(name);
        }
    }

    public static List getNum(int num, Supplier sup) {
        List list = new ArrayList<>(num);
        for (int i = 0; i < num; i++) {
            list.add(sup.get());
        }
        return list;
    }

    public static String strHander(String str, Function fun) {
        return fun.apply(str);
    }

    public static void con(Integer num, Consumer con) {
        con.accept(num);
    }

    /**
     * 满足条件的放在集合中
     */

    public static List fileNames(List list,Predicate predicate){
        List listVal = new ArrayList<> ();
        for (String s : list){
            if (predicate.test(s)){
                listVal.add(s);
            }
        }
        return listVal;
    }
}
JDK8新特性_第2张图片
其他接口
3.方法引用与构造器引用

当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
(实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!)
方法引用:使用操作符 “ ::” 将方法名和对象或类的名字分隔开来。
如下三种主要使用情况 :
 对象 :: 实例方法
 类 :: 静态方法
 类 ::实例方法

public class Test1 {
    public static void main(String[] args) {
        test3();
    }

    public static void test3(){
        Supplier  user = User::new;
        User user1 = user.get();
        System.out.println(user1);

       Function fun = User::new;
       User user2 = fun.apply("123");
        System.out.println(user2);


    }
    public static void test2(){
        User user = new User();
        user.setUsername("adasdas");
        user.setPassword("rgregre");
        System.out.println(user);
        Supplier sup = () -> user.getUsername();
        String str = sup.get();
        System.out.println(str);


        Supplier sup2 = user::getPassword;
        String password = sup2.get();
        System.out.println(password);
    }
    public static void test1(){
        Consumer consumer = (x) -> System.out.println(x);

        PrintStream ps = System.out;
        Consumer consume1 = ps::println;
        consume1.accept("hahahah");
    }
}

注意: 当 需要引用方法的第一个参数是调用对象,并且第二个参数是需要引用方法的第二个 参数( ( 或无参数) ) 时 : ClassName::methodName
构造器 引用
格式: ClassName :: new 与函数式接口相结合,自动与函数式接口中方法兼容。可以把构造器引用赋值给定义的方法,与构造器参数列表要与接口中抽象方法的参数列表一致!

数组引用 格式: type[] :: new

public static void test4(){
    Function fun = (x)->new  String[x];
    String[] strs = fun.apply(10);
    System.out.println(strs.length);

    Function fun1 = String[]::new;
    String[] strs1 = fun1.apply(10);
    System.out.println(strs1.length);
}
4.Stream API

Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一
个则是 Stream API( java.util.stream .*) 。
Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对
集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。
使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数
据库查询。也可以使用 Stream API 来并行执行操作。简而言之,
Stream API 提供了一种高效且易于使用的处理数据的方式。

什么是 Stream
流 (Stream) 到底是什么呢 ?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,流讲的是计算! ”
注意:
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。


JDK8新特性_第3张图片
Stream

创建 Stream 的四种方式
Java8 中的 Collection 接口被扩展,提供了两个获取流的方法 :
 default Stream stream() : 返回一个顺序流
 default Stream parallelStream() : 返回一个并行流

1.可以通过 Collection 系列的集合提供 stream 或者 parallelStream
2.通过 Arrays的方法 数组流
3.通过Stream的静态方法 of()
4.第四种方式 创建无限流

/**
 * Stream的3个步骤
 * 1.创建Stream
 * 

* 2.中间操作 *

*

* 3.终止操作 */ public class StreamAPI1 { public static void main(String[] args) { //1.可以通过 Collection 系列的集合提供 stream 或者 parallelStream List list = new ArrayList<>(); Stream stream1 = list.stream(); //2.通过 Arrays的方法 数组流 User[] users = new User[10]; Stream stream = Arrays.stream(users); //3.通过Stream的静态方法 of() Stream stream2 = Stream.of("asda", "123"); //4.第四种方式 创建无限流 //1 迭代 Stream.iterate(0, (x) -> x + 2) .limit(20) .forEach(System.out::println); //2生成 Stream.generate(() -> Math.random()).limit(20).forEach(System.out::println); } }

中间操作
筛选与切片
1.filter - 接收Lambda,从流中排序某些元素
2.limit - 截断流 使其元素不超过给定数量
3.skip(n) - 跳过元素 ,返回一个扔掉了前面n个元素的流,若流中元素不足n个.则返回一个空流,与limit互补
4.distinct - 筛选 通过流所生成的 equals 和 hashCode 去除重复元素


JDK8新特性_第4张图片
筛选与切片
public class StreamAPI1 {

    public static void main(String[] args) {
        //中间操作
        //筛选与切片
        //1.filter - 接收Lambda,从流中排序某些元素
        //2.limit - 截断流 使其元素不超过给定数量
        //3.skip(n) - 跳过元素 ,返回一个扔掉了前面n个元素的流,若流中元素不足n个.则返回一个空流,与limit互补
        //4.distinct - 筛选 通过流所生成的 equals 和 hashCode 去除重复元素

        List list = new ArrayList<>();
        list.add("234");
        list.add("ger2vsdv34");
        list.add("2bvadfvb34");
        list.add("afb2gb34");
        list.add("awseg234");
        //中间操作不会执行任何操作
        //内部迭代 具体操作由 Stream API 完成
        //1.filter - 接收Lambda,从流中排序某些元素
        Stream stringStream = list.stream().filter((e) -> {
            System.out.println("Stream 的中间操作");
            return e.contains("g");
        });
        //终止操作
        stringStream.forEach(System.out::println);
        System.out.println("------------------------------------------------");
        //2.limit - 截断流 使其元素不超过给定数量
        Stream limit = list.stream().filter((e) -> e.contains("2")).limit(2);
        limit.forEach(System.out::println);
        System.out.println("-------------------------------------------------");
        list.stream().filter((e) -> e.contains("2")).limit(2).forEach(System.out::println);

        //3.skip(n) - 跳过元素 ,返回一个扔掉了前面n个元素的流,若流中元素不足n个.则返回一个空流,与limit互补
        System.out.println("------------------------------------------------");
        list.stream().filter((e) -> e.contains("g")).skip(2).forEach(System.out::println);
        //4.distinct - 筛选 通过流所生成的 equals 和 hashCode 去除重复元素
        System.out.println("------------------------------------------------");
        list.stream().filter((e) -> e.contains("g")).skip(2).distinct().forEach(System.out::println);
    }
}

映射


JDK8新特性_第5张图片
映射
public class StreamAPI1 {

    public static void main(String[] args) {
        //中间操作
        //映射
        //map 映射
        List list = new ArrayList<>();
        list.add("234");
        list.add("ger2vsdv34");
        list.add("2bvadfvb34");
        list.add("afb2gb34");
        list.add("awseg234");
        System.out.println("------------------------------------");
        list.stream().map((e) ->e.toUpperCase()).forEach(System.out::println);
        System.out.println("------------------------------------");
        //返回 Boolean
        Stream g = list.stream().map((e) -> e.contains("g"));

        System.out.println("------------------------------------");
        List list1 = new ArrayList();
        List list2 = new ArrayList();
        list1.add("1");
        list1.add("2");
        list1.add("3");
        list2 = list1.stream().map(string -> {
            return "stream().map()处理之后:" + string;
        }).collect(Collectors.toList());
        list2.stream().forEach(string -> {
            System.out.println(string);
        });

        //flatMap映射 接收一个函数作为参数 将流中的每个值都转换为另外一个流 然后把流合并
    }
}

排序


JDK8新特性_第6张图片
排序
public class StreamAPI1 {

    public static void main(String[] args) {
        //中间操作
        //排序操作
        List list = new ArrayList<>();
        list.add("234");
        list.add("ger2vsdv34");
        list.add("2bvadfvb34");
        list.add("afb2gb34");
        list.add("awseg234");
        System.out.println("---------------------------");
        list.stream().sorted().forEach(System.out::println);
        System.out.println("---------------------------");
        list.stream().sorted((e1,e2)-> -(e2.compareTo(e1))).forEach(System.out::println);
    }
}

终端操作会从流的流水线生成结果。其结果可以是任何不是流的
值,例如:List、Integer,甚至是 void


JDK8新特性_第7张图片
查找与匹配

//终止操作
//allMatch - 检查是否匹配所有元素
//anyMatch - 检查是否只是匹配一个元素
//noneMatch - 检查是否没有匹配的元素
//findFirst - 返回第一个元素
//findAny - 返回当前流的任意元素
//count - 返回流中的总个数
//max - 返回流中的最大值
//min - 返回流中的最小值

public class StreamAPI1 {

    public static void main(String[] args) {
        //终止操作
        //allMatch - 检查是否匹配所有元素
        //anyMatch - 检查是否只是匹配一个元素
        //noneMatch - 检查是否没有匹配的元素
        //findFirst - 返回第一个元素
        //findAny -  返回当前流的任意元素
        //count - 返回流中的总个数
        //max - 返回流中的最大值
        //min - 返回流中的最小值
        List list = new ArrayList<>();
        list.add("234");
        list.add("ger2vsdv34");
        list.add("2bvadfvb34");
        list.add("afb2gb34");
        list.add("awseg234");
        System.out.println("--------------------------");
        boolean g = list.stream().allMatch((e) -> e.contains("g"));
        System.out.println(g);
        System.out.println("--------------------------");
         g = list.stream().anyMatch((e) -> e.contains("g"));
        System.out.println(g);
        System.out.println("--------------------------");
         g = list.stream().noneMatch((e) -> e.contains("g"));
        System.out.println(g);
        System.out.println("--------------------------");
        Optional first = list.stream().sorted().findFirst();
        System.out.println(first.get());
        System.out.println("--------------------------");
        Optional any = list.stream().filter((e) -> e.equals("234")).findAny();
        System.out.println(any.get());
        System.out.println("--------------------------");
        long count = list.stream().count();
        System.out.println(count);
        System.out.println("--------------------------");
        Optional max = list.stream().max((e1, e2) -> e1.compareTo(e2));
        System.out.println(max.get());
        System.out.println("--------------------------");
        Optional min = list.stream().min((e1, e2) -> e1.compareTo(e2));
        System.out.println(min.get());
    }
}
JDK8新特性_第8张图片
方法和规约
public class Employee {

    private int id;
    private String name;
    private int age;
    private double salary;
    private Status status;

    public Employee() {
    }

    public Employee(String name) {
        this.name = name;
    }

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Employee(int id, String name, int age, double salary) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    public Employee(int id, String name, int age, double salary, Status status) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
        this.status = status;
    }

    public Status getStatus() {
        return status;
    }

    public void setStatus(Status status) {
        this.status = status;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public String show() {
        return "测试方法引用!";
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + id;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        long temp;
        temp = Double.doubleToLongBits(salary);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Employee other = (Employee) obj;
        if (age != other.age)
            return false;
        if (id != other.id)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        if (Double.doubleToLongBits(salary) != Double.doubleToLongBits(other.salary))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + ", status=" + status
                + "]";
    }

    public enum Status {
        FREE, BUSY, VOCATION;
    }

}
public class TestStreamAPI3 {

    List emps = Arrays.asList(
            new Employee(102, "李四", 79, 6666.66, Employee.Status.BUSY),
            new Employee(101, "张三", 18, 9999.99, Employee.Status.FREE),
            new Employee(103, "王五", 28, 3333.33, Employee.Status.VOCATION),
            new Employee(104, "赵六", 8, 7777.77, Employee.Status.BUSY),
            new Employee(104, "赵六", 8, 7777.77, Employee.Status.FREE),
            new Employee(104, "赵六", 8, 7777.77, Employee.Status.FREE),
            new Employee(105, "田七", 38, 5555.55, Employee.Status.BUSY)
    );

    //3. 终止操作
    /**
        归约
        reduce(T identity, BinaryOperator) / reduce(BinaryOperator) ——可以将流中元素反复结合起来,得到一个值。
     */
    @Test
    public void test1() {
        List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        Integer sum = list.stream()
                .reduce(0, (x, y) -> x + y);

        System.out.println(sum);

        System.out.println("----------------------------------------");

        Optional op = emps.stream()
                .map(Employee::getSalary)
                .reduce(Double::sum);

        System.out.println(op.get());
    }


    /**
     * collect——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
     */

    @Test
    public void test3() {
        List list = emps.stream()
                .map(Employee::getName)
                .collect(Collectors.toList());

        list.forEach(System.out::println);

        System.out.println("----------------------------------");

        Set set = emps.stream()
                .map(Employee::getName)
                .collect(Collectors.toSet());

        set.forEach(System.out::println);

        System.out.println("----------------------------------");

        HashSet hs = emps.stream()
                .map(Employee::getName)
                .collect(Collectors.toCollection(HashSet::new));

        hs.forEach(System.out::println);
    }

    @Test
    public void test4() {
        Optional max = emps.stream()
                .map(Employee::getSalary)
                .collect(Collectors.maxBy(Double::compare));

        System.out.println(max.get());

        Optional op = emps.stream()
                .collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));

        System.out.println(op.get());

        Double sum = emps.stream()
                .collect(Collectors.summingDouble(Employee::getSalary));

        System.out.println(sum);

        Double avg = emps.stream()
                .collect(Collectors.averagingDouble(Employee::getSalary));

        System.out.println(avg);

        Long count = emps.stream()
                .collect(Collectors.counting());

        System.out.println(count);

        System.out.println("--------------------------------------------");

        DoubleSummaryStatistics dss = emps.stream()
                .collect(Collectors.summarizingDouble(Employee::getSalary));

        System.out.println(dss.getMax());
    }

    //分组
    @Test
    public void test5() {
        Map> map = emps.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));

        System.out.println(map);
    }

    //多级分组
    @Test
    public void test6() {
        Map>> map = emps.stream()
                .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
                    if (e.getAge() >= 60) {
                        return "老年";
                    } else if (e.getAge() >= 35) {
                        return "中年";
                    } else {
                        return "成年";
                    }

                })));

        System.out.println(map);
    }

    //分区
    @Test
    public void test7() {
        Map> map = emps.stream()
                .collect(Collectors.partitioningBy((e) -> e.getSalary() >= 5000));

        System.out.println(map);
    }

    //
    @Test
    public void test8() {
        String str = emps.stream()
                .map(Employee::getName)
                .collect(Collectors.joining(",", "----", "----"));

        System.out.println(str);
    }

    @Test
    public void test9() {
        Optional sum = emps.stream()
                .map(Employee::getSalary)
                .collect(Collectors.reducing(Double::sum));

        System.out.println(sum.get());
    }
}

收集 拿到返回值


JDK8新特性_第9张图片
收集
public class Test2 {
    public static void main(String[] args) {
        Integer[] integers = new Integer[]{1, 23, 4, 5, 6, 7, 800};
        Object[] objects = Arrays.stream(integers).map((x) -> x * x).collect(Collectors.toList()).toArray();
        for (Object o : objects ){
            System.out.println(o);
        }
    }
}

Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表


JDK8新特性_第10张图片
收集器实例

JDK8新特性_第11张图片
收集器实例
并行流和串行流

并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。

Java 8 中将并行进行了优化,我们可以很容易的对数据进行并行操作。Stream API 可以声明性地通过 parallel() 与sequential() 在并行流与顺序流之间进行切换。


JDK8新特性_第12张图片
Fork/Join框架

Fork/Join 框架与传统线程池的区别
采用 “工作窃取”模式(work-stealing):
当执行新的任务时它可以将其拆分分成更小的任务执行,并将小任务加到线
程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。相对于一般的线程池实现,fork/join框架的优势体现在对其中包含的任务的处理方式上.在一般的线程池中,如果一个线程正在执行的任务由于某些原因无法继续运行,那么该线程会处于等待状态.而在fork/join框架实现中,如果某个子问题由于等待另外一个子问题的完成而无法继续运行.那么处理该子问题的线程会主动寻找其他尚未运行的子问题来执行.这种方式减少了线程的等待时间,提高了性能


public class ForkJoinCalculate extends RecursiveTask{
    private static final long serialVersionUID = 13475679780L;
    
    private long start;
    private long end;

    /**
     * 临界值
     */
    private static final long THRESHOLD = 10000L;
    
    public ForkJoinCalculate(long start, long end) {
        this.start = start;
        this.end = end;
    }
    
    @Override
    protected Long compute() {
        long length = end - start;
        
        if(length <= THRESHOLD){
            long sum = 0;
            
            for (long i = start; i <= end; i++) {
                sum += i;
            }
            
            return sum;
        }else{
            long middle = (start + end) / 2;
            
            ForkJoinCalculate left = new ForkJoinCalculate(start, middle);
            left.fork(); //拆分,并将该子任务压入线程队列
            
            ForkJoinCalculate right = new ForkJoinCalculate(middle+1, end);
            right.fork();
            
            return left.join() + right.join();
        }
        
    }

}
public class TestForkJoin {

    public static void main(String[] args) {
        test1();
        test2();
        test3();
    }

    public static void test1() {
        long start = System.currentTimeMillis();

        ForkJoinPool pool = new ForkJoinPool();
        ForkJoinTask task = new ForkJoinCalculate(0L, 100000000L);

        long sum = pool.invoke(task);
        System.out.println(sum);

        long end = System.currentTimeMillis();

        //112-1953-1988-2654-2647-20663-113808
        System.out.println("耗费的时间为: " + (end - start));
    }

    public static void test2() {
        long start = System.currentTimeMillis();

        long sum = 0L;

        for (long i = 0L; i <= 100000000L; i++) {
            sum += i;
        }

        System.out.println(sum);

        long end = System.currentTimeMillis();
        //34-3174-3132-4227-4223-31583
        System.out.println("耗费的时间为: " + (end - start));
    }


    public static void test3() {
        long start = System.currentTimeMillis();

        Long sum = LongStream.rangeClosed(0L, 100000000L)
                .parallel()
                .sum();

        System.out.println(sum);

        long end = System.currentTimeMillis();

        //2061-2053-2086-18926
        System.out.println("耗费的时间为: " + (end - start));
    }

}

打印结果

5000000050000000
耗费的时间为: 121
5000000050000000
耗费的时间为: 37
5000000050000000
耗费的时间为: 121
5.接口中的默认方法与静态方法

接口中的默认方法
接口默认方法的 ” 类优先 ” 原则
若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时
 选择父类中的方法。如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。
 接口冲突。如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突

public interface MyInto {
    /**
     * 实际上使用很少
     * @return 返回 "哈哈哈"
     */
    default String getName() {
        return "哈哈哈";
    }

    public static void show(){
        System.out.println("MyInto.show");
    }

    /**
     * 但是接口就是定义规范 其他
     */
    void getInfo();

}
6.新时间日期 API

使用 LocalDate 、LocalTime 、LocalDateTime
 LocalDate、LocalTime、LocalDateTime 类的实例是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息。


JDK8新特性_第13张图片
方法
public class DateAPINew {
    public static void main(String[] args) {

        /**
         * 1. LocalDate  LocalTime   LocalDateTime
         *
         */
        LocalDateTime ldt = LocalDateTime.now();
        int dayOfMonth = ldt.getDayOfMonth();
        System.out.println(ldt);
        LocalDateTime of = LocalDateTime.of(2020, 10, 20, 12, 45, 30);
        System.out.println(of);
        System.out.println(dayOfMonth);

        LocalDateTime localDateTime = ldt.plusYears(2);
        System.out.println(localDateTime);
        System.out.println("---------------------------");
        /**
         * Instant 获取时间戳
         */
        Instant instant = Instant.now();
        OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
        System.out.println(offsetDateTime);
        System.out.println(instant.toEpochMilli());
        Instant instant1 = Instant.ofEpochMilli(instant.toEpochMilli()+1000000000);
        System.out.println(instant1);

        /**
         * Duration 计算两个时间之间的间隔
         * Period 计算两个日期之间的间隔
         */
        System.out.println("---------------------------------");
        Instant now = Instant.now();
        try {
            Thread.sleep(1000);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Instant now1 = Instant.now();
        Duration duration = Duration.between(now,now1);
        System.out.println(duration.toMillis());

        System.out.println("--------------------");
        LocalTime lc = LocalTime.now();
        try {
            Thread.sleep(1000);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        LocalTime lc1 = LocalTime.now();
        System.out.println(Duration.between(lc,lc1).toMillis());

        /**
         * 日期之间的间隔
         */
        System.out.println("-----------------------");
        LocalDate ld = LocalDate.now();
        LocalDate ld1 = LocalDate.of(2012,12,21);
        Period p = Period.between(ld1,ld);
        System.out.println(p.getYears());
    }
}

 TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下个周日”等操作。
 TemporalAdjusters : 该类通过静态方法提供了大量的常用 TemporalAdjuster 的实现

public class DateAPINew {
    public static void main(String[] args) {

        //时间矫正器
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);

        //设置时间
        LocalDateTime ldt2 = ldt.withDayOfMonth(10);
        System.out.println(ldt2);

        LocalDateTime with = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
        System.out.println(with);
    }
}

时间格式化和时区的处理
java.time.format.DateTimeFormatter 类:该类提供了三种格式化方法:
 预定义的标准格式
 语言环境相关的格式
 自定义的格式

public class DateAPINew {
    public static void main(String[] args) {
        //DateTimeFormatter
        //指定格式化方式
        DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
        LocalDateTime ldt = LocalDateTime.now();
        String format = formatter.format(ldt);
        System.out.println(format);

        DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String format1 = formatter1.format(ldt);
        System.out.println(format1);
        LocalDateTime parse = LocalDateTime.parse(format1, formatter1);
        System.out.println(parse);

        System.out.println("---------------------");
        //对时区的操作
        Set availableZoneIds = ZoneId.getAvailableZoneIds();
        Iterator iterator = availableZoneIds.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

        LocalDateTime time = LocalDateTime.now(ZoneId.of("US/Pacific"));
        System.out.println(time);

        System.out.println(LocalDateTime.now());
        System.out.println(LocalDate.now());
        System.out.println(LocalTime.now());
    }
}
7.其他新特性
Optional类

Optional 类(java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。
常用方法:
Optional.of(T t) : 创建一个 Optional 实例
Optional.empty() : 创建一个空的 Optional 实例
Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
isPresent() : 判断是否包含值
orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
flatMap(Function mapper):与 map 类似,要求返回值必须是Optional

重复注解与类型注解

Java 8对注解处理提供了两点改进:可重复的注解及可用于子类型的注解

@Repeatable(MyAnno2.class)
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER,ElementType.LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno {
    String value() default "hahah";
}
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER,ElementType.LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno2 {
    MyAnno[] value();
}
@MyAnno("xixixi")
@MyAnno("hahahaha")
@MyAnno
public class Test6 {
}
JavaScript 引擎 Nashorn

Nashorn 允许在 JVM 上开发运行 JavaScript 应用,允许 Java 与 JavaScript相互调用。

Base64

在 Java 8 中,Base64 编码成为了 Java 类库的标准。Base64 类同时还提供了对 URL、MIME 友好的编码器与解码器。

其他

更好的类型推测机制:Java 8 在类型推测方面有了很大的提高,这就使代码更整洁,不需要太多的强制类型转换了。

编译器优化:Java 8 将方法的参数名加入了字节码中,这样在运行时通过反射就能获取到参数名,只需要在编译时使用-parameters 参数。

并行(parallel)数组:支持对数组进行并行处理,主要是 parallelSort()方法,它可以在多核机器上极大提高数组排序的速度。

并发(Concurrency):在新增 Stream 机制与 Lambda 的基础之上,加入了一些新方法来支持聚集操作。

Nashorn 引擎 jjs:基于 Nashorn 引擎的命令行工具。它接受一些JavaScript

源代码为参数,并且执行这些源代码。

类依赖分析器 jdeps:可以显示 Java 类的包级别或类级别的依赖。

JVM 的 PermGen 空间被移除:取代它的是 Metaspace(JEP 122)。

你可能感兴趣的:(JDK8新特性)