JDK8新特性

簡介

1.速度更快
2.代碼更少(Lambda表達式)
3.強大的Stream API
4.便于并行
5.最大化減少空指針異常 Optical

JDK8新特性列表

1.Lambda 表達式
2.函數(shù)式接口
3.方法引用與構造器引用
4.Stream API
5.接口中的默認方法與靜態(tài)方法
6.新時間日期 API
7.其他新特性

1.Lambda 表達式

為什么使用 Lambda 表達式?
Lambda 是一個 匿名函數(shù),我們可以把 Lambda表達式理解為是 一段可以傳遞的代碼(將代碼像數(shù)據(jù)一樣進行傳遞)??梢詫懗龈啙?、更靈活的代碼。作為一種更緊湊的代碼風格,使Java的語言表達能力得到了提升。

/**
 * 左側  Lambda 表達式的參數(shù)列表
 * 右側  Lambda 所需執(zhí)行的功能,即 Lambda 提
 * 語法格式1:無參數(shù) 返回值
 *      () -> System.out.println("hello");
 * 語法格式2:有一個參數(shù)  有返回值
 *      (t) -> System.out.println(t);
 * 語法格式3:有一個參數(shù) 小括號可以省略不寫 有返回值
 *      t -> System.out.println(t);
 * 語法格式4:有2個參數(shù) 有多條語句
 *          (x, y) -> {
 *             System.out.println("函數(shù)式接口");
 *             return x.compareTo(y);
 *         };
 * 語法格式5:有2個參數(shù) 只有一條語句 大括號和return可以都省了 如上
 *
 * 語法格式6.參數(shù)列表的數(shù)據(jù)類型可以不寫,,因為JVM可以推斷類型,如果寫,都要寫
 */

從匿名類到 Lambda 的轉換

public class LambdaTest {
    /**
     * 左側  Lambda 表達式的參數(shù)列表
     * 右側  Lambda 所需執(zhí)行的功能,即 Lambda 提
     * 語法格式1:無參數(shù) 返回值
     *      () -> System.out.println("hello");
     * 語法格式2:有一個參數(shù)  有返回值
     *      (t) -> System.out.println(t);
     * 語法格式3:有一個參數(shù) 小括號可以省略不寫 有返回值
     *      t -> System.out.println(t);
     * 語法格式4:有2個參數(shù) 有多條語句
     *          (x, y) -> {
     *             System.out.println("函數(shù)式接口");
     *             return x.compareTo(y);
     *         };
     * 語法格式5:有2個參數(shù) 只有一條語句 大括號和return可以都省了 如上
     *
     * 語法格式6.參數(shù)列表的數(shù)據(jù)類型可以不寫,,因為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<String> consumer = t -> System.out.println(t);
        consumer.accept("hello");

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

什么 是函數(shù)式接口
? 只包含一個抽象方法的接口,稱為 函數(shù)式接口。
? 你可以通過 Lambda 表達式來創(chuàng)建該接口的對象。(若 Lambda
表達式拋出一個受檢異常,那么該異常需要在目標接口的抽象方
法上進行聲明)。
? 我們可以在任意函數(shù)式接口上使用 @ FunctionalInterface 注解,
這樣做可以檢查它是否是一個函數(shù)式接口,同時 javadoc 也會包
含一條聲明,說明這個接口是一個函數(shù)式接口

@FunctionalInterface
public interface MyFun {
    Integer getVal(Integer num);
}
public class LambdaTest3 {
    /**
     * 左側  Lambda 表達式的參數(shù)列表
     * 右側  Lambda 所需執(zhí)行的功能,即 Lambda 提
     * 函數(shù)式接口:接口中只有一個抽象方法的接口,稱為函數(shù)式接口 
     * 可以使用  @FunctionalInterface 修飾
     * 就可以檢查是不是函數(shù)式接口
     */
    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);
    }
}

作為遞 參數(shù)傳遞 Lambda 將 表達式:為了將 Lambda 表達式作為參數(shù)傳遞,接收 Lambda 該 表達式的參數(shù)類型必須是與該 Lambda 表達式兼容的函數(shù)式接口的類型

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<String> 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<Integer> getNum(int num, Supplier<Integer> sup) {
        List<Integer> list = new ArrayList<>(num);
        for (int i = 0; i < num; i++) {
            list.add(sup.get());
        }
        return list;
    }

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

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

    /**
     * 滿足條件的放在集合中
     */

    public static List<String> fileNames(List<String> list,Predicate<String> predicate){
        List<String> listVal = new ArrayList<> ();
        for (String s : list){
            if (predicate.test(s)){
                listVal.add(s);
            }
        }
        return listVal;
    }
}
其他接口
3.方法引用與構造器引用

當要傳遞給Lambda體的操作,已經(jīng)有實現(xiàn)的方法了,可以使用方法引用!
(實現(xiàn)抽象方法的參數(shù)列表,必須與方法引用方法的參數(shù)列表保持一致!)
方法引用:使用操作符 “ ::” 將方法名和對象或類的名字分隔開來。
如下三種主要使用情況 :
? 對象 :: 實例方法
? 類 :: 靜態(tài)方法
? 類 ::實例方法

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

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

       Function<String, User> 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<String> sup = () -> user.getUsername();
        String str = sup.get();
        System.out.println(str);


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

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

注意: 當 需要引用方法的第一個參數(shù)是調用對象,并且第二個參數(shù)是需要引用方法的第二個 參數(shù)( ( 或無參數(shù)) ) 時 : ClassName::methodName
構造器 引用
格式: ClassName :: new 與函數(shù)式接口相結合,自動與函數(shù)式接口中方法兼容??梢园褬嬙炱饕觅x值給定義的方法,與構造器參數(shù)列表要與接口中抽象方法的參數(shù)列表一致!

數(shù)組引用 格式: type[] :: new

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

    Function<Integer, String[]> 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 中處理集合的關鍵抽象概念,它可以指定你希望對
集合進行的操作,可以執(zhí)行非常復雜的查找、過濾和映射數(shù)據(jù)等操作。
使用Stream API 對集合數(shù)據(jù)進行操作,就類似于使用 SQL 執(zhí)行的數(shù)
據(jù)庫查詢。也可以使用 Stream API 來并行執(zhí)行操作。簡而言之,
Stream API 提供了一種高效且易于使用的處理數(shù)據(jù)的方式。

什么是 Stream
流 (Stream) 到底是什么呢 ?
是數(shù)據(jù)渠道,用于操作數(shù)據(jù)源(集合、數(shù)組等)所生成的元素序列?!凹现v的是數(shù)據(jù),流講的是計算! ”
注意:
①Stream 自己不會存儲元素。
②Stream 不會改變源對象。相反,他們會返回一個持有結果的新Stream。
③Stream 操作是延遲執(zhí)行的。這意味著他們會等到需要結果的時候才執(zhí)行。


Stream

創(chuàng)建 Stream 的四種方式
Java8 中的 Collection 接口被擴展,提供了兩個獲取流的方法 :
? default Stream<E> stream() : 返回一個順序流
? default Stream<E> parallelStream() : 返回一個并行流

1.可以通過 Collection 系列的集合提供 stream 或者 parallelStream
2.通過 Arrays的方法 數(shù)組流
3.通過Stream的靜態(tài)方法 of()
4.第四種方式 創(chuàng)建無限流

/**
 * Stream的3個步驟
 * 1.創(chuàng)建Stream
 * <p>
 * 2.中間操作
 * <p>
 * <p>
 * 3.終止操作
 */
public class StreamAPI1 {

    public static void main(String[] args) {
        //1.可以通過 Collection 系列的集合提供 stream 或者 parallelStream
        List<String> list = new ArrayList<>();
        Stream<String> stream1 = list.stream();
        //2.通過 Arrays的方法 數(shù)組流
        User[] users = new User[10];
        Stream<User> stream = Arrays.stream(users);

        //3.通過Stream的靜態(tài)方法 of()
        Stream<String> stream2 = Stream.of("asda", "123");

        //4.第四種方式  創(chuàng)建無限流
        //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 - 截斷流 使其元素不超過給定數(shù)量
3.skip(n) - 跳過元素 ,返回一個扔掉了前面n個元素的流,若流中元素不足n個.則返回一個空流,與limit互補
4.distinct - 篩選 通過流所生成的 equals 和 hashCode 去除重復元素


篩選與切片
public class StreamAPI1 {

    public static void main(String[] args) {
        //中間操作
        //篩選與切片
        //1.filter - 接收Lambda,從流中排序某些元素
        //2.limit - 截斷流 使其元素不超過給定數(shù)量
        //3.skip(n) - 跳過元素 ,返回一個扔掉了前面n個元素的流,若流中元素不足n個.則返回一個空流,與limit互補
        //4.distinct - 篩選 通過流所生成的 equals 和 hashCode 去除重復元素

        List<String> list = new ArrayList<>();
        list.add("234");
        list.add("ger2vsdv34");
        list.add("2bvadfvb34");
        list.add("afb2gb34");
        list.add("awseg234");
        //中間操作不會執(zhí)行任何操作
        //內部迭代 具體操作由 Stream API 完成
        //1.filter - 接收Lambda,從流中排序某些元素
        Stream<String> stringStream = list.stream().filter((e) -> {
            System.out.println("Stream 的中間操作");
            return e.contains("g");
        });
        //終止操作
        stringStream.forEach(System.out::println);
        System.out.println("------------------------------------------------");
        //2.limit - 截斷流 使其元素不超過給定數(shù)量
        Stream<String> 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);
    }
}

映射


映射
public class StreamAPI1 {

    public static void main(String[] args) {
        //中間操作
        //映射
        //map 映射
        List<String> 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<Boolean> g = list.stream().map((e) -> e.contains("g"));

        System.out.println("------------------------------------");
        List<String> list1 = new ArrayList();
        List<String> 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映射 接收一個函數(shù)作為參數(shù) 將流中的每個值都轉換為另外一個流 然后把流合并
    }
}

排序


排序
public class StreamAPI1 {

    public static void main(String[] args) {
        //中間操作
        //排序操作
        List<String> 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


查找與匹配

//終止操作
//allMatch - 檢查是否匹配所有元素
//anyMatch - 檢查是否只是匹配一個元素
//noneMatch - 檢查是否沒有匹配的元素
//findFirst - 返回第一個元素
//findAny - 返回當前流的任意元素
//count - 返回流中的總個數(shù)
//max - 返回流中的最大值
//min - 返回流中的最小值

public class StreamAPI1 {

    public static void main(String[] args) {
        //終止操作
        //allMatch - 檢查是否匹配所有元素
        //anyMatch - 檢查是否只是匹配一個元素
        //noneMatch - 檢查是否沒有匹配的元素
        //findFirst - 返回第一個元素
        //findAny -  返回當前流的任意元素
        //count - 返回流中的總個數(shù)
        //max - 返回流中的最大值
        //min - 返回流中的最小值
        List<String> 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<String> first = list.stream().sorted().findFirst();
        System.out.println(first.get());
        System.out.println("--------------------------");
        Optional<String> 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<String> max = list.stream().max((e1, e2) -> e1.compareTo(e2));
        System.out.println(max.get());
        System.out.println("--------------------------");
        Optional<String> min = list.stream().min((e1, e2) -> e1.compareTo(e2));
        System.out.println(min.get());
    }
}
方法和規(guī)約
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<Employee> 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<Integer> 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<Double> op = emps.stream()
                .map(Employee::getSalary)
                .reduce(Double::sum);

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


    /**
     * collect——將流轉換為其他形式。接收一個 Collector接口的實現(xiàn),用于給Stream中元素做匯總的方法
     */

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

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

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

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

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

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

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

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

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

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

        Optional<Employee> 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<Employee.Status, List<Employee>> map = emps.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));

        System.out.println(map);
    }

    //多級分組
    @Test
    public void test6() {
        Map<Employee.Status, Map<String, List<Employee>>> 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);
    }

    //分區(qū)
    @Test
    public void test7() {
        Map<Boolean, List<Employee>> 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<Double> sum = emps.stream()
                .map(Employee::getSalary)
                .collect(Collectors.reducing(Double::sum));

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

收集 拿到返回值


收集
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 接口中方法的實現(xiàn)決定了如何對流執(zhí)行收集操作(如收集到 List、Set、Map)。但是 Collectors 實用類提供了很多靜態(tài)方法,可以方便地創(chuàng)建常見收集器實例,具體方法與實例如下表


收集器實例

收集器實例
并行流和串行流

并行流就是把一個內容分成多個數(shù)據(jù)塊,并用不同的線程分別處理每個數(shù)據(jù)塊的流。

Java 8 中將并行進行了優(yōu)化,我們可以很容易的對數(shù)據(jù)進行并行操作。Stream API 可以聲明性地通過 parallel() 與sequential() 在并行流與順序流之間進行切換。


Fork/Join框架

Fork/Join 框架與傳統(tǒng)線程池的區(qū)別
采用 “工作竊取”模式(work-stealing):
當執(zhí)行新的任務時它可以將其拆分分成更小的任務執(zhí)行,并將小任務加到線
程隊列中,然后再從一個隨機線程的隊列中偷一個并把它放在自己的隊列中。相對于一般的線程池實現(xiàn),fork/join框架的優(yōu)勢體現(xiàn)在對其中包含的任務的處理方式上.在一般的線程池中,如果一個線程正在執(zhí)行的任務由于某些原因無法繼續(xù)運行,那么該線程會處于等待狀態(tài).而在fork/join框架實現(xiàn)中,如果某個子問題由于等待另外一個子問題的完成而無法繼續(xù)運行.那么處理該子問題的線程會主動尋找其他尚未運行的子問題來執(zhí)行.這種方式減少了線程的等待時間,提高了性能


public class ForkJoinCalculate extends RecursiveTask<Long>{
    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<Long> 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.接口中的默認方法與靜態(tài)方法

接口中的默認方法
接口默認方法的 ” 類優(yōu)先 ” 原則
若一個接口中定義了一個默認方法,而另外一個父類或接口中又定義了一個同名的方法時
? 選擇父類中的方法。如果一個父類提供了具體的實現(xiàn),那么接口中具有相同名稱和參數(shù)的默認方法會被忽略。
? 接口沖突。如果一個父接口提供一個默認方法,而另一個接口也提供了一個具有相同名稱和參數(shù)列表的方法(不管方法是否是默認方法),那么必須覆蓋該方法來解決沖突

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

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

    /**
     * 但是接口就是定義規(guī)范 其他
     */
    void getInfo();

}
6.新時間日期 API

使用 LocalDate 、LocalTime 、LocalDateTime
? LocalDate、LocalTime、LocalDateTime 類的實例是不可變的對象,分別表示使用 ISO-8601日歷系統(tǒng)的日期、時間、日期和時間。它們提供了簡單的日期或時間,并不包含當前的時間信息。也不包含與時區(qū)相關的信息。


方法
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 : 該類通過靜態(tài)方法提供了大量的常用 TemporalAdjuster 的實現(xiàn)

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

時間格式化和時區(qū)的處理
java.time.format.DateTimeFormatter 類:該類提供了三種格式化方法:
? 預定義的標準格式
? 語言環(huán)境相關的格式
? 自定義的格式

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("---------------------");
        //對時區(qū)的操作
        Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
        Iterator<String> 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<T> 類(java.util.Optional) 是一個容器類,代表一個值存在或不存在,原來用 null 表示一個值不存在,現(xiàn)在 Optional 可以更好的表達這個概念。并且可以避免空指針異常。
常用方法:
Optional.of(T t) : 創(chuàng)建一個 Optional 實例
Optional.empty() : 創(chuàng)建一個空的 Optional 實例
Optional.ofNullable(T t):若 t 不為 null,創(chuàng)建 Optional 實例,否則創(chuàng)建空實例
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 上開發(fā)運行 JavaScript 應用,允許 Java 與 JavaScript相互調用。

Base64

在 Java 8 中,Base64 編碼成為了 Java 類庫的標準。Base64 類同時還提供了對 URL、MIME 友好的編碼器與解碼器。

其他

更好的類型推測機制:Java 8 在類型推測方面有了很大的提高,這就使代碼更整潔,不需要太多的強制類型轉換了。

編譯器優(yōu)化:Java 8 將方法的參數(shù)名加入了字節(jié)碼中,這樣在運行時通過反射就能獲取到參數(shù)名,只需要在編譯時使用-parameters 參數(shù)。

并行(parallel)數(shù)組:支持對數(shù)組進行并行處理,主要是 parallelSort()方法,它可以在多核機器上極大提高數(shù)組排序的速度。

并發(fā)(Concurrency):在新增 Stream 機制與 Lambda 的基礎之上,加入了一些新方法來支持聚集操作。

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

源代碼為參數(shù),并且執(zhí)行這些源代碼。

類依賴分析器 jdeps:可以顯示 Java 類的包級別或類級別的依賴。

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

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • JDK8新特性介紹 JDK8新特性:? 1,Lambda表達式? 2,新的日期API? 3,引入Optional?...
    偏偏愛吃梨閱讀 780評論 0 2
  • 閱讀原文 Chapter 14 . JDK8新特性 14.1 Lambda 表達式 Lambda 是一個匿名函數(shù),...
    GeekGray閱讀 1,086評論 0 10
  • 官方新特性說明地址 下面對幾個常用的特性做下重點說明。 一、Lambda表達式 1.1 函數(shù)式編程 百科介紹:h...
    丘八老爺閱讀 1,043評論 0 6
  • 為什么要學Java8 Java8讓你的編程變得更容易 充分穩(wěn)定的利用計算機硬件資源 Lambda lambda 是...
    李慶雪閱讀 4,614評論 0 5
  • java8新特性學習 java8的特點 速度更快(修改了HasMap、HasSet、CurrentHasMap等存...
    ZGYSYY閱讀 980評論 0 0

友情鏈接更多精彩內容