1. 程式人生 > >Java8的新特性(四)

Java8的新特性(四)

並行流與序列流

什麼是並行流

在這裡插入圖片描述

我們先了解一下什麼是Fork/Join框架

在這裡插入圖片描述

Fork/Join框架和傳統的執行緒池的區別

在這裡插入圖片描述


應用Fork/Join計算100000000的和:

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

測試程式碼如下:

    @Test
    public void test() {
        Instant start = Instant.now();
        ForkJoinPool pool = new ForkJoinPool();
        ForkJoinTask<Long> task = new ForkJoinCalculate(0, 100000000L);
        Long sum = pool.invoke(task);
        System.out.println(sum);
        Instant end = Instant.now();
        System.out.println("耗費時間為:"+Duration.between(start, end).toMillis());
    }

執行結果如下圖:
在這裡插入圖片描述
數值越大,它的效率體現的就越明顯;
在Java8裡面可以利用並行流就可以這樣來寫:它的底層就是Fork/Join

	@Test
    public void test3() {
        Instant start = Instant.now();
        LongStream.rangeClosed(0, 100000000L)
                .parallel()
                .reduce(0, Long::sum);
        Instant end = Instant.now();
        System.out.println("耗費時間為:"+Duration.between(start, end).toMillis());
    }

Optional容器類

什麼是Optional類

在這裡插入圖片描述

Optional類的常用方法

一、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

  • Optional.of(T t) : 建立一個 Optional 例項
	@Test
    public void test1() {
        Optional<Employee> op = Optional.of(new Employee());
        Employee employee = op.get();
        System.out.println(employee);
    }

執行結果如下:沒有傳任何的引數,這個時候,結果就是預設的值

Employee [id=0, name=null, age=0, salary=0.0, status=null]

需要注意的地方就是:
如果這裡面傳入了一個Null值,那麼這裡就是會發生空指標異常,原來的我們定位空指標異常要一行一行的去定位,非常的麻煩。它的思想就是:如果傳進來了一個Null,在這一行就會發生空指標的異常,方便我們快速定位到空指標異常發生的地方:

Optional<Employee> op = Optional.of(null);

  • Optional.empty() : 建立一個空的 Optional 例項
	@Test
    public void test2() {
        Optional<Employee> op = Optional.empty();
        System.out.println(op.get());
    }

在這一行發生了空指標異常:

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

Optional.ofNullable(T t):若 t 不為 null,建立 Optional 例項,否則建立空例項

  • 若 t 不為 null,建立 Optional 例項
	@Test
    public void test3() {
        Optional<Employee> op = Optional.ofNullable(new Employee());
        System.out.println(op.get());
    }
  • 若t為Null,那麼則建立空的例項
	@Test
    public void test3() {
        Optional<Employee> op = Optional.ofNullable(null);
        System.out.println(op.get());
    }

  • isPresent() : 判斷是否包含值
    我們可以進行判斷:有值的時候,就正常的呼叫;如果沒有值的話,那麼就什麼都不做;
	@Test
    public void test4() {
        Optional<Employee> op = Optional.ofNullable(null);
        if (op.isPresent()) {
            System.out.println(op.get());
        }
    }

  • orElse(T t) : 如果呼叫物件包含值,返回該值,否則返回t
    如果有值的話,那麼就返回值,如果沒有值的話,那麼我們就返回這個備用的值:T
    如果有值的話,那麼就是返回了這個值:
	@Test
    public void test5() {
        Optional<Employee> op = Optional.ofNullable(new Employee());
        if (op.isPresent()) {
            System.out.println(op.get());
        }
        Employee employee = op.orElse(new Employee(1, "張三", 18, 888.88, Employee.Status.FREE));
        System.out.println(employee);
    }

結果如下:

Employee [id=0, name=null, age=0, salary=0.0, status=null]
Employee [id=0, name=null, age=0, salary=0.0, status=null]

如果沒有值的話,那麼就是返回我們備用的值

	@Test
    public void test5() {
        Optional<Employee> op = Optional.ofNullable(null);
        if (op.isPresent()) {
            System.out.println(op.get());
        }
        Employee employee = op.orElse(new Employee(1, "張三", 18, 888.88, Employee.Status.FREE));
        System.out.println(employee);
    }

這個時候,就是隻輸出一個值:也就是當為空時候,輸出我們備用的值

Employee [id=1, name=張三, age=18, salary=888.88, status=FREE]

  • orElseGet(Supplier s) :如果呼叫物件包含值,返回該值,否則返回 s 獲取的值
    orElseGet這個方法裡面的引數是一個供給型的介面,可以實現具體的功能:
	@Test
    public void test6() {
        Optional<Employee> op = Optional.ofNullable(null);
        Employee employee = op.orElseGet(() -> new Employee());
        System.out.println(employee);
    }

  • map(Function f): 如果有值對其處理,並返回處理後的Optional,否則返回 Optional.empty()
	@Test
    public void test7() {
        Optional<Employee> op = Optional.ofNullable(new Employee(1, "張三", 18, 888.88, Employee.Status.FREE));
        Optional<String> str = op.map((e) -> e.getName());
        System.out.println(str.get());
    }

  • flatMap(Function mapper):與 map 類似,要求返回值必須是Optional
    進一步避免空指標異常
    @Test
    public void test8() {
        Optional<Employee> op = Optional.ofNullable(new Employee(1, "張三", 18, 888.88, Employee.Status.FREE));
        Optional<String> opStr = op.flatMap((e) -> Optional.of(e.getName()));
        System.out.println(opStr.get());
    }

一般我們在建立可能為空的屬性的時候,我們就是可以這樣來寫了:
我們就是可以用Optional這個類來進行封裝一下:

private Optional<Godness> godness = Optional.empty();

這個時候,就是可以避免空指標異常了:
在這裡插入圖片描述
這個時候,就是可以避免空指標異常了;
如果,我們傳了,就是我們傳的值,如果沒有傳的話,那麼也是有預設的值,就有效的避免了空指標的異常了:
在這裡插入圖片描述


介面中的預設方法與靜態方法

介面中的預設方法

在這裡插入圖片描述
介面中的預設方法有一個類優先的原則:
在這裡插入圖片描述

  1. 有一個介面,裡面有一個預設的方法:
public interface MyFun {
    default String getName() {
        return "Hello World";
    }
}
  1. 有一個類,裡面也有一個與上面介面同樣名字的方法:
public class MyClass {
    public String getName() {
        return "I love Java";
    }
}
  1. 此時,有一個類同時繼承了上面的類和實現了上面的介面:
public class SubClass extends MyClass implements MyFun{

}
  1. 現在,我們建立SubClass這個類的例項,並且呼叫了例項的getName方法:
    public static void main(String[]args){
        SubClass subClass = new SubClass();
        System.out.println(subClass.getName());
    }
  1. 此時,執行的結果如下:
    在這裡插入圖片描述

需要注意的地方:
如果一個類裡面實現了多個介面,而這多個接口裡面有重名的方法,那麼這個時候,在實現裡面必須指定重寫哪一個介面的對應的方法;
在這裡插入圖片描述

介面中的靜態方法:

在這裡插入圖片描述

public interface MyInterface {
    default String getName() {
        return "hello java";
    }

    public static void show() {
        System.out.println("介面中的靜態方法");
    }
}

用法還是和類裡面的靜態方法一樣用的:

    public static void main(String[]args){
        MyInterface.show();
    }

傳統時間格式化的執行緒安全問題

全新的時間都在這幾個包下面:
在這裡插入圖片描述

這些都是常用的:
在這裡插入圖片描述


	public static void main(String[]args) throws Exception{
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

        Callable<Date> task = new Callable<Date>() {
            @Override
            public Date call() throws Exception {
                return sdf.parse("20181111");
            }
        };

        /** 建立長度為10的執行緒池 */
        ExecutorService pool = Executors.newFixedThreadPool(10);
        List<Future<Date>> results = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            results.add((pool.submit(task)));
        }
        for (Future<Date> future : results) {
            System.out.println(future.get());
        }
        pool.shutdown();
    }

如下圖:
在這裡插入圖片描述

看執行結果,是存線上程安全的問題的:
在這裡插入圖片描述

傳統的時間API都存線上程安全的問題;
原來,我們面對執行緒安全問題,我們可以對其加鎖;

  • 我們可以使用ThreadLocal
public class DateFormatThreadLocal {
    private static final ThreadLocal<DateFormat> df = new ThreadLocal<>(){
        @Override
        protected DateFormat initialValue() {
            return new SimpleDateFormat("yyyyMMdd");
        }
    };

    public static Date convert(String source) throws ParseException {
        return df.get().parse(source);
    }
}

然後,我們就是可以這樣來用:

public static void main(String[]args) throws Exception{

        Callable<Date> task = new Callable<Date>() {
            @Override
            public Date call() throws Exception {
                return DateFormatThreadLocal.convert("20181111");
            }
        };

        /** 建立長度為10的執行緒池 */
        ExecutorService pool = Executors.newFixedThreadPool(10);
        List<Future<Date>> results = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            results.add((pool.submit(task)));
        }
        for (Future<Date> future : results) {
            System.out.println(future.get());
        }
        pool.shutdown();
    }

這個時候的執行結果就是:
在這裡插入圖片描述


Java8全新的API:它是執行緒安全的

public class TestSimpleDateFormat {
    public static void main(String[]args) throws Exception{

        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");

        Callable<LocalDate> task = new Callable<LocalDate>() {
            @Override
            public LocalDate call() throws Exception {
                return LocalDate.parse("20181111",dtf);
            }
        };

        /** 建立長度為10的執行緒池 */
        ExecutorService pool = Executors.newFixedThreadPool(10);
        List<Future<LocalDate>> results = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            results.add((pool.submit(task)));
        }
        for (Future<LocalDate> future : results) {
            System.out.println(future.get());
        }
        pool.shutdown();
    }
}

相關推薦

java8特性:Stream流的使用

Java5的時候就引入了自動裝箱拆箱的功能, 在對包裝型別進行數學計算的時候,包裝型別就會被自動拆箱成基本型別, 而將一個基本型別的值賦值給一個包裝型別的變數或者放入集合中時基本型別又會被自動裝箱成包裝型別,這個過程是需要消耗計算效能的。Java8的包裝型別的流的計算過程中同樣包含了對基本型別的自動裝箱和拆箱

Java8特性------介面中可以定義方法體

 Java8比起以前的版本存在很大的變化,我們知道在之前的版本中介面只能是定義抽象的方法,是不能定義實現的,但是在java8環境下,這個不可能已經變得可能。下面我們通過例子一步一步的來講解下java8

Java8特性

並行流與序列流 什麼是並行流 我們先了解一下什麼是Fork/Join框架 Fork/Join框架和傳統的執行緒池的區別 應用Fork/Join計算100000000的和: public class ForkJoinCalculate extends

Java8特性---Lambda表示式

Java8新特性之Lambda表示式 Lambda的語法格式 語法格式一:無引數,無返回值 語法格式二:有一個引數,並且無返回值 語法格式三:若只有一個引

Java8特性方法引用、構造器引用、陣列引用

目錄: 1、方法引用 1.1、物件 :: 例項方法 1.2、類 :: 靜態方法 1.3、類 ::例項方法 2、構造器引用 2.1、介紹 2.2、使用 3、陣列引用 3.1、介紹 3.2、使用 1、方法引用 若lambda體中的內容有方法已經實現了,

Java8特性日期時間的API

1、新時間日期API java.time – 包含值物件的基礎包 java.time.chrono – 提供對不同的日曆系統的訪問 java.time.format – 格式化和解析時間和日期 java.time.temporal – 包括底層框架和擴

Java8特性方法引用

方法引用 方法引用其實就是Lambda表示式的簡寫,標誌是 :: 1、和Lambda表示式比較 public class Java8Test { public s

Android O 8.0特性 官方Demo

主要採用的google翻譯,不當之處,還望指正.Code Samples 程式碼示例Use the code samples below to learn about Android 8.0 (API level 26) capabilities and APIs. To d

MQTT 5.0 特性Clean Start 與 Session Expiry Interval

前言 MQTT v5.0 中的 Clean Start 與 Session Expiry Interval,對於有 MQTT v3

Java8特性

強大的Stream API 瞭解Stream Java8中有兩個最為重要的改變。第一個是Lambda表示式;另外一個則是Stream API(java.util.stream.*)。 Stream是Java8中處理集合的關鍵抽象概念,它可以指定你希望對集合進行的操作,可以執行非常複雜

Java8特性

四大內建核心函式式介面 Java8 內建的四大核心函式式介面 Consumer : 消費型介面 --> void accept(T t); Supplier : 供給型介面 -->T get(); Function<T, R> : 函式型介

java8特性簡述十大特性

截止稿前,java10都已經發布了,現在我們來討論一下java8(2014年3月釋出)。 本文的討論,只是一個簡述,更加具體的,各位可以參照各自的專題講解 說在前面 你真的開始用JDK8了嗎? 如果你沒有用上一些新特性,請別說自己使用了Java8。 Java 8可謂

java8特性方法引用、構造器引用

前言: 接上一篇文章:Java8新特性(內建的核心函式式介面)http://blog.csdn.net/xinghuo0007/article/details/78603908 我們知道使用了L

java8特性 λ、stream 與 預設介面方法

1.lambda λ表示式本質上是一個匿名方法,用來方便地實現函式介面。也就是說,λ表示式主要用於替換以前廣泛使用的內部匿名類。  讓我們來看下面這個例子:     public int add(int x, int y) {         return x + y;  

Java8特性lambda、Stream、Optional

1、λ表示式lambda表示式:λ表示式是Java8新增的一個特性,《Core Java》中的對它的解析是——“一個可傳遞的程式碼塊,可以在以後執行一次或多次”。從日常開發的角度來看,它可以簡化我們的很

java8新增特性---Lambda表達式

使用 watermark 成員變量 arr mar .net [] size mark Lambda表達式也成為閉包,是java語言層次上的改變,Lambda同意把函數作為一個方法的參數(函數作為參數傳遞進方法中),或者把代碼看成數據。函數

MySQL 8.0.2復制特性翻譯

ogl 防止 將不 地址 arc -- 等待 download 日誌 譯者:知數堂星耀隊 MySQL 8.0.2復制新特性 MySQL 8 正在變得原來越好,而且這也在我們MySQL復制研發團隊引起了一陣熱潮。我們一直致力於全面提升MySQL復制,通過引入新的和一些有趣

php7特性:面向物件部分

1)、PHP 7 支援new class 來例項化一個匿名類這可以用來替代一些"用後即焚"的完整類定義。 2)、Closure::call():將一個閉包函式動態繫結到一個新的物件例項並呼叫執行該函式 3)、use:可以使用一個 use 從同一個 namespace 中匯入類、函

特性2---一致性初始化,使用者自定義初值列

一致性初始化 引入原因 在沒有引入之前,變數的初始化有許多方式 (如小括號,大括號,賦值號),且不同變數和類又有不同的初始化方式。(如,結構體能用{}初始化,類用{}則會出錯。) int i=1; int i(1); int i = int(1); test

特性4---Foreach,String Literal

Foreach foreach是新引入的一種for迴圈形式,常見語法如下: decl是coll集合中每個元素的宣告 for(decl: coll) { //run } for的轉換 對於集合種提供成員函式如begin(),或者end()等產生的foreach如下