2016-10-25 24 views
5

Sự khác nhau giữa mã này là gì?Khi nào chúng ta nên sử dụng Nhà cung cấp trong Java 8?

Supplier<LocalDate> s1 = LocalDate::now; 
LocalDate s2 = LocalDate.now(); 

System.out.println(s1.get()); //2016-10-25 
System.out.println(s2); //2016-10-25 

Tôi bắt đầu học các giao diện chức năng trong Java 8 và không hiểu lợi ích nào cung cấp Nhà cung cấp. Khi nào và làm thế nào, chính xác, chúng ta nên sử dụng anh ta. Nhà cung cấp có cải thiện hiệu suất hoặc có thể là lợi ích trên mức trừu tượng không?

Cảm ơn câu trả lời của bạn! Và nó không phải là câu hỏi trùng lặp bởi vì tôi đã sử dụng tìm kiếm và không tìm thấy những gì tôi cần.

CẬP NHẬT 1: Ý của bạn là gì?

Supplier<Long> s1 = System::currentTimeMillis; 
    Long s2 = System.currentTimeMillis(); 

    System.out.println(s1.get()); //1477411877817 
    System.out.println(s2); //1477411877817 
    try { 
     Thread.sleep(3000l); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
    System.out.println(s1.get()); //1477411880817 - different 
    System.out.println(s2); //1477411877817 
+2

's2' sẽ cung cấp cho bạn "bây giờ" tại thời điểm mà 's2' được chỉ định. 's1.get()' sẽ cung cấp cho bạn "bây giờ" tại điểm khi bạn gọi 'get()'. Điều đó có thể không giống nhau nếu bạn đã thông qua 'Nhà cung cấp' ở đâu đó để được sử dụng khi được yêu cầu. Sau đó, nếu bạn gọi 's1.get()' một lần nữa sau đó, bạn sẽ nhận được một thời gian khác một lần nữa. – khelwood

+0

@khelwood, tôi không nhận được câu hỏi và cập nhật, vui lòng kiểm tra. – badCoder

+1

Sử dụng nó khi bạn cần phải vượt qua khả năng để có được _multiple values_ vào _another method._ Đó là khá nhiều 100% các trường hợp sử dụng hợp lệ. –

Trả lời

2

Nó chắc chắn không cải thiện hiệu suất. Câu hỏi của bạn tương tự như câu hỏi này: Tại sao chúng ta sử dụng các biến? Chúng ta có thể chỉ cần tính toán lại mọi thứ mỗi lần chúng ta cần. Đúng?

Nếu bạn cần sử dụng một phương pháp nhiều lần, nhưng nó có một cú pháp dài dòng.

Giả sử bạn có một lớp có tên là MyAmazingClass và bạn có phương thức với tên MyEvenBetterMethod (tĩnh) và bạn cần gọi 15 lần ở 15 vị trí khác nhau trong mã của bạn. Tất nhiên, bạn có thể làm một cái gì đó giống như ...

int myVar = MyAmazingClass.MyEvenBetterMethod(); 
// ... 
int myOtherVar = MyAmazingClass.MyEvenBetterMethod(); 
// And so on... 

... nhưng bạn cũng có thể làm

Supplier<MyAmazingClass> shorter = MyAmazingClass::MyEvenBetterMethod; 

int myVar = shorter.get(); 
// ... 
int myOtherVar = shorter.get(); 
// And so on... 
+4

Chắc chắn đó sẽ là 'Nhà cung cấp '. Và nó không có gì để làm với hiệu suất hoặc làm thế nào wordy một phương pháp. Có một sự khác biệt ngữ nghĩa. – biziclop

7

Bạn đang bối rối giao diện chức năng và tài liệu tham khảo phương pháp. Supplier chỉ là một giao diện, tương tự như Callable, mà bạn nên biết kể từ Java 5, khác biệt duy nhất là Callable.call được phép ném kiểm tra Exception s, không giống như Supplier.get. Vì vậy, các giao diện này sẽ có các trường hợp sử dụng tương tự.

Bây giờ, các giao diện này cũng xảy ra là giao diện chức năng, ngụ ý rằng chúng có thể được thực hiện như một tham chiếu phương thức, trỏ đến phương thức hiện có sẽ được gọi khi phương thức giao diện được gọi.

Vì vậy, trước khi Java 8, bạn phải viết

Future<Double> f=executorService.submit(new Callable<Double>() { 
    public Double call() throws Exception { 
     return calculatePI(); 
    } 
}); 
/* do some other work */ 
Double result=f.get(); 

và bây giờ, bạn có thể viết

Future<Double> f=executorService.submit(() -> calculatePI()); 
/* do some other work */ 
Double result=f.get(); 

hoặc

Future<Double> f=executorService.submit(MyClass::calculatePI); 
/* do some other work */ 
Double result=f.get(); 

Câu hỏi khi sử dụngCallable hasn 't thay đổi ở tất cả.

Tương tự như vậy, câu hỏi khi nào sử dụng Supplier không phụ thuộc vào cách bạn thực hiện nó, nhưng mà API bạn sử dụng, ví dụ:

CompletableFuture<Double> f=CompletableFuture.supplyAsync(MyClass::calculatePI); 
/* do some other work */ 
Double result=f.join();// unlike Future.get, no checked exception to handle... 
1

tôi sẽ đi qua một kịch bản mà chúng ta nên sử dụng Supplier<LocalDate> thay vì LocalDate .

Mã trực tiếp thực hiện cuộc gọi đến các phương pháp tĩnh như LocalDate.now() rất khó để kiểm tra đơn vị. Hãy xem xét một kịch bản mà chúng tôi muốn đơn vị thử nghiệm một phương pháp getAge() để tính toán tuổi của một người:

class Person { 
    final String name; 
    private final LocalDate dateOfBirth; 

    Person(String name, LocalDate dateOfBirth) { 
     this.name = name; 
     this.dateOfBirth = dateOfBirth; 
    } 

    long getAge() { 
     return ChronoUnit.YEARS.between(dateOfBirth, LocalDate.now()); 
    } 
} 

này hoạt động tốt trong sản xuất. Nhưng một bài kiểm tra đơn vị sẽ phải đặt ngày của hệ thống thành giá trị đã biết hoặc được cập nhật hàng năm để mong đợi tuổi được trả về sẽ được tăng thêm bởi một, cả hai giải pháp khá đáng lo ngại.

Một giải pháp tốt hơn là để thử nghiệm đơn vị bơm vào một ngày đã biết trong khi vẫn cho phép mã sản xuất sử dụng LocalDate.now(). Có thể một cái gì đó như thế này:

class Person { 
    final String name; 
    private final LocalDate dateOfBirth; 
    private final LocalDate currentDate; 

    // Used by regular production code 
    Person(String name, LocalDate dateOfBirth) { 
     this(name, dateOfBirth, LocalDate.now()); 
    } 

    // Visible for test 
    Person(String name, LocalDate dateOfBirth, LocalDate currentDate) { 
     this.name = name; 
     this.dateOfBirth = dateOfBirth; 
     this.currentDate = currentDate; 
    } 

    long getAge() { 
     return ChronoUnit.YEARS.between(dateOfBirth, currentDate); 
    } 

} 

Hãy xem xét một trường hợp sinh nhật của người đó đã trôi qua kể từ khi đối tượng được tạo. Với việc triển khai này, getAge() sẽ dựa trên thời điểm đối tượng Person được tạo thay vì ngày hiện tại. Chúng tôi có thể giải quyết điều này bằng cách sử dụng Supplier<LocalDate>:

class Person { 
    final String name; 
    private final LocalDate dateOfBirth; 
    private final Supplier<LocalDate> currentDate; 

    // Used by regular production code 
    Person(String name, LocalDate dateOfBirth) { 
     this(name, dateOfBirth,()-> LocalDate.now()); 
    } 

    // Visible for test 
    Person(String name, LocalDate dateOfBirth, Supplier<LocalDate> currentDate) { 
     this.name = name; 
     this.dateOfBirth = dateOfBirth; 
     this.currentDate = currentDate; 
    } 

    long getAge() { 
     return ChronoUnit.YEARS.between(dateOfBirth, currentDate.get()); 
    } 

    public static void main(String... args) throws InterruptedException { 
     // current date 2016-02-11 
     Person person = new Person("John Doe", LocalDate.parse("2010-02-12")); 
     printAge(person); 
     TimeUnit.DAYS.sleep(1); 
     printAge(person); 
    } 

    private static void printAge(Person person) { 
     System.out.println(person.name + " is " + person.getAge()); 
    } 
} 

Kết quả sẽ là một cách chính xác:

John Doe is 5 
John Doe is 6 

kiểm tra đơn vị của chúng tôi có thể tiêm các "bây giờ" ngày như thế này:

@Test 
void testGetAge() { 
    Supplier<LocalDate> injectedNow =()-> LocalDate.parse("2016-12-01"); 
    Person person = new Person("John Doe", LocalDate.parse("2004-12-01"), injectedNow); 
    assertEquals(12, person.getAge()); 
} 
Các vấn đề liên quan