欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Java的閉包

 更新時間:2015年07月12日 11:51:22   投稿:goldensun  
這篇文章主要介紹了詳解Java的閉包,作者從Lambda和默認(rèn)方法等重要特性深入講解,極力推薦!需要的朋友可以參考下

 在2013年將發(fā)布的 JavaSE8 中將包含一個叫做 Lambda Project 的計劃,在今年6月份的 JSR-335 草案中有描述。

 JSR-335 將閉包引入了 Java 。閉包在現(xiàn)在的很多流行的語言中都存在,例如 C++、C# 。閉包允許我們創(chuàng)建函數(shù)指針,并把它們作為參數(shù)傳遞。在這篇文章中,我們將粗略的看一遍Java8的特性,并介紹Lambda表達(dá)式。而且我將試著放一些樣例程序來解釋一些概念和語法。

Java 編程語言給我們提供了接口的概念,接口里可以定義抽象的方法。接口定義了 API,并希望用戶或者供應(yīng)商來實現(xiàn)這些方法。很多時候,我們并不為一些接口創(chuàng)建獨立的實現(xiàn)類,我們通過寫一個匿名內(nèi)部類來寫一個內(nèi)聯(lián)的接口實現(xiàn)。

匿名類使用的非常廣泛。匿名內(nèi)部類使用的最常見的場景就是事件處理器了。其次匿名內(nèi)部類還常被用在多線程的程序中,我們通常寫匿名內(nèi)部類,而不是創(chuàng)建 Runnable/Callable 接口的實現(xiàn)類。

就像我們討論的一樣,一個匿名類就是一個內(nèi)聯(lián)的給定的接口的實現(xiàn)。通常我們將這個實現(xiàn)類的對象作為參數(shù)傳遞給一個方法,然后這個方法將在內(nèi)部調(diào)用傳遞過來的實現(xiàn)類的方法。故這種接口叫做回調(diào)接口,這些方法叫做回調(diào)方法。


雖然匿名類到處都在使用,但是他們還是有很多問題。第一個主要問題是復(fù)雜。這些類讓代碼的層級看起來很亂很復(fù)雜,也稱作 Vertical Problem 。第二,他們不能訪問封裝類的非 final 成員。this 這個關(guān)鍵字將變得很有迷惑性。如果一個匿名類有一個與其封裝類相同的成員名稱,內(nèi)部變量將會覆蓋外部的成員變量,在這種情況下,外部的成員在匿名類內(nèi)部將是不可見的,甚至不能通過 this 關(guān)鍵字來訪問。因為 this 關(guān)鍵字值得是匿名類對象本身而不是他的封裝類的對象。
 

public void anonymousExample() {
  String nonFinalVariable = "Non Final Example";
  String variable = "Outer Method Variable";
  new Thread(new Runnable() {
    String variable = "Runnable Class Member";
    public void run() {
      String variable = "Run Method Variable";
      //Below line gives compilation error.
      //System.out.println("->" + nonFinalVariable);
      System.out.println("->" + variable);
      System.out.println("->" + this.variable);
    }
  }).start();
}

輸出是:
 

->Run Method Variable
->Runnable Class Member

這個例子很好的說明了我上面所說的這個問題,而 Lambda 表達(dá)式幾乎解決了匿名內(nèi)部類帶來的所有問題。在我們進一步探討 lambda 表達(dá)式之前,讓我們來看一看 Functional Interfaces。


Functional Interfaces

Functional Interfaces 是一個只有單個方法的接口,這代表了這個方法契約。

上面的定義中的只有一個實際上并沒有那么簡單。這段有些不懂,請讀者查看原文(The ‘Single' method can exist in the form of multiple abstract methods that are inherited from superinterfaces. But in that case the inherited methods should logically represent a single method or it might redundantly declare a method that is provided by classes like Object, e.g. toString.)

下面的例子清楚的展示了怎樣理解 Functional Interfaces 的概念。
 

interface Runnable { void run(); }
// Functional
interface Foo { boolean equals(Object obj); }
// Not functional; equals is already an implicit member
interface Bar extends Foo {int compare(String o1, String o2); }
// Functional; Bar has one abstract non-Object method
interface Comparator {
 boolean equals(Object obj);
 int compare(T o1, T o2);
}
// Functional; Comparator has one abstract non-Object method
interface Foo {int m();  Object clone(); }
// Not functional; method Object.clone is not public
interface X { int m(Iterable arg); }
interface Y { int m(Iterable arg); }
interface Z extends X, Y {}
// Functional: two methods, but they have the same signature

大多數(shù)回調(diào)接口都是 Functional Interfaces。例如 Runnable,Callable,Comparator 等等。以前被稱作 SAM(Single Abstract Method)


Lambda 表達(dá)式

我們上邊說過,匿名類的一個主要問題是是代碼的層級看起來很亂,也就是 Vertical Problem 了,Lamdba 表達(dá)式實際上就是匿名類,只不過他們的結(jié)構(gòu)更輕量,更短。Lambda 表達(dá)式看起來像方法。他們有一個正式的參數(shù)列表和這些參數(shù)的塊體表達(dá)。
 

(String s)-> s.lengh;
() -> 43;
(int x, int y) -> x + y;

上面的例子的意思是,第一個表達(dá)式接收一個 String 變量作為參數(shù),然后返回字符串的長度。第二個不帶任何參數(shù),并返回43。最后,第三個接受兩個整數(shù) x 和 y ,并返回其和。

在看了許多文字后,終于,我可以給出第一個 Lambda 表達(dá)式的例子了,這個例子運行在 JavaSE8 的預(yù)覽版下:
 

public class FirstLambdaExpression {
  public String variable = "Class Level Variable";
  public static void main(String[] arg) {
    new FirstLambdaExpression().lambdaExpression();
  }
  public void lambdaExpression(){
    String variable = "Method Local Variable";
    String nonFinalVariable = "This is non final variable";
    new Thread (() -> {
      //Below line gives compilation error
      //String variable = "Run Method Variable"
      System.out.println("->" + variable);
      System.out.println("->" + this.variable);
    }).start();
  }
}

輸出是:
 

->Method Local Variable
->Class Level Variable


你可以比較一些使用 Lambda 表達(dá)式和使用匿名內(nèi)部類的區(qū)別。我們可以清楚的說,使用 Lambda 表達(dá)式的方式寫匿名類解決了變量可見性的問題。你可以看一下代碼中的注釋, Lambda 表達(dá)式不允許創(chuàng)建覆蓋變量。

通常的 Lambda 表達(dá)式的語法包括一個參數(shù)列表,箭頭關(guān)鍵字"->"最后是主體。主體可以是表達(dá)式(單行語句)也可以是多行語句塊。如果是表達(dá)式,將被計算后返回,如果是多行的語句塊,就看起來跟方法的語句塊很相似了,可以使用 return 來指定返回值。break 和 continue  只能用在循環(huán)內(nèi)部。

為什么選擇這個特殊的語法形式呢,因為目前 C# 和 Scala 中通常都是這種樣式,也算是 Lambda 表達(dá)式的通用寫法。這樣的語法設(shè)計基本上解決了匿名類的復(fù)雜性。但是與此同時他也是非常靈活的,例如,如果方法體是單個表達(dá)式,大括號和 return 語句都是不需要的。表達(dá)式的結(jié)果就是作為他自己的返回值。這種靈活性可以保持代碼簡潔。

 Lambda 表達(dá)式用作匿名類,因此他們可以靈活運用在其他模塊或在其他 Lambda 表達(dá)式(嵌套的 Lambda 表達(dá)式)。
 

//Lambda expression is enclosed within methods parameter block.
//Target interface type is the methods parameter type.
String user = doSomething(() -> list.getProperty(“propName”);
//Lambda expression is enclosed within a thread constructor
//target interface type is contructors paramter i.e. Runnable
new Thread (() -> {
  System.out.println("Running in different thread");
}).start();


如果你仔細(xì)看看 lambda 表達(dá)式,您將看到,目標(biāo)接口類型不是一個表達(dá)式的一部分。編譯器會幫助推斷 lambda 表達(dá)式的類型與周圍環(huán)境。

Lambda 表達(dá)式必須有一個目標(biāo)類型,而他們可以適配任意可能的目標(biāo)類型。當(dāng)目標(biāo)類型是一個接口的時候,下面的條件必須滿足,才能編譯正確:

  •     接口應(yīng)該是一個 functional interface
  •     表達(dá)式的參數(shù)數(shù)量和類型必須與 functional interface 中聲明的一致
  •     返回值類型必須兼容 functional interface 中方法的返回值類型
  •     拋出的異常表達(dá)式必須兼容 functional interface 中方法的拋出異常聲明

由于編譯器可以通過目標(biāo)類型的聲明中得知參數(shù)類型和個數(shù),所以在 Lambda 表達(dá)式中,可以省略參數(shù)類型聲明。
 

Comparator c = (s1, s2) -> s1.compareToIgnoreCase(s2);

而且,如果目標(biāo)類型中聲明的方法只接收一個參數(shù)(很多時候都是這樣的),那么參數(shù)的小括號也是可以不寫的,例如:
 

ActionListenr listenr = event -> event.getWhen();


一個很明顯的問題來了,為什么 Lambda 表達(dá)式不需要一個指定的方法名呢?

答案是:Lambda 表達(dá)式只能用于 functional interface ,而 functional interface 只有一個方法。

當(dāng)我們確定一個 functional interface 來創(chuàng)建 Lambda 表達(dá)式的時候,編譯器可以感知 functional interface 中方法的簽名,并且檢查給定的表達(dá)式是否匹配。

這種靈活的語法幫助我們避免了使用匿名類的 Vertical Problem ,而且不會帶來 Horizontal Problem(單行語句非常長)。

Lambda 表達(dá)式的語法是上下文相關(guān)的,但是這些并不是第一次出現(xiàn)。Java SE 7添加的diamond operators 也有這個概念,通過上下文推斷類型。
 

void invoke(Runnable r) {r.run()}
void Future invoke(Callable r) {return c.compute()}
//above are two methods, both takes parameter of type functional interface
Future s = invoke(() ->"Done"); //Which invoke will be called?


上面問題的答案是調(diào)用接收Callable參數(shù)的方法。在這種情況下編譯器會通過不同參數(shù)類型的重載解決。當(dāng)有不止一個適用的重載方法,編譯器也檢查lambda表達(dá)式與相應(yīng)的目標(biāo)類型的兼容性。簡單的說,上面的invoke方法期望一個返回,但是只有一個invoke方法具有返回值。

Lambda表達(dá)式可以顯式的轉(zhuǎn)換為指定的目標(biāo)類型,只要跟對應(yīng)的類型兼容??匆幌孪旅娴某绦颍覍崿F(xiàn)了三種Callable,而且都將其轉(zhuǎn)換為Callable類型。
 

public class FirstSightWithLambdaExpressions {
  public static void main(String[] args) {
    List list = Arrays.asList(
      (Callable)()->"callable 1",
      (Callable) ()->"callable 2",
      (Callable) ()->"callable 3");
    ExecutorService e = Executors.newFixedThreadPool(2);
    List futures = null;
    try {
      futures = e.invokeAll(list);
      new FirstSightWithLambdaExpressions().dumpList(futures);
    } catch (InterruptedException | ExecutionException e1) {
      e1.printStackTrace();
    }
    e.shutdown();
  }
  public void dumpList(List list) throws InterruptedException,
       ExecutionException {
    for (Future future : list) {
      System.out.println(future.get());
    }
  }
}

正如我們前面討論的一樣,匿名類不能訪問周圍環(huán)境中非final的變量。但是Lambda表達(dá)式里就沒有這個限制。

目前,該定義的 functional interfaces 只適用于接口。我試著對一個只有一個抽象方法的抽象類創(chuàng)建一個 lambda 表達(dá)式,但出了一個編譯錯誤。按照 jsr - 335,未來版本的 lambda 表達(dá)式可能支持 Functional Classes。


方法引用
方法引用被用作引用一個方法而不調(diào)用它。
Lambda 表達(dá)式允許我們定義一個匿名的方法,并將它作為 Functional interface 的一個實例。方法引用跟 Lambda 表達(dá)式很像,他們都需要一個目標(biāo)類型,但是不同的是方法引用不提供方法的實現(xiàn),他們引用一個已經(jīng)存在的類或者對象的方法。
 

System::getProperty
"abc"::length
String::length
super::toString
ArrayList::new

上面的語句展示了方法和構(gòu)造函數(shù)的引用的通用語法。這里我們看到引入了一個新的操作符“::'(雙冒號)。我尚不清楚確切名稱為這個操作符,但是 JSR 指它作為分隔符,維基百科頁面是指它作為一個范圍解析操作符。作為我們的參考,本教程的范圍內(nèi),我們將簡單地將它作為分隔符。
目標(biāo)引用或者說接收者被放在提供者和分隔符的后面。這形成了一個表達(dá)式,它能夠引用一個方法。在最后聲明上述代碼,該方法的名字是“new”。這個表達(dá)式引用的是 ArrayList 類的構(gòu)造方法(下一節(jié)再討論構(gòu)造方法的引用)

再進一步了解這個之前,我想讓你看一看方法引用的強大之處,我創(chuàng)建了一個簡單的 Employee 數(shù)組的排序程序。
 

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public class MethodReference {
  public static void main (String[] ar){
    Employee[] employees = {new Employee("Nick"), new Employee("Robin"), new      Employee("Josh"), new Employee("Andy"), new Employee("Mark")};
    System.out.println("Before Sort:");
    dumpEmployee(employees);
    Arrays.sort(employees, Employee::myCompare);
    System.out.println("After Sort:");
    dumpEmployee(employees);
  }
  public static void dumpEmployee(Employee[] employees){
    for(Employee emp : Arrays.asList(employees)){
      System.out.print(emp.name+", ");
    }
    System.out.println();
  }
}
class Employee {
  String name;
  Employee(String name) {
   this.name = name;
  }
  public static int myCompare(Employee emp1, Employee emp2) {
    return emp1.name.compareTo(emp2.name);
  }
}

輸出是:
 

Before Sort: Nick, Robin, Josh, Andy, Mark, 
After Sort: Andy, Josh, Mark, Nick, Robin,

輸出沒什么特別,Employee 是一個非常簡單的類,只有一個 name 屬性。靜態(tài)方法 myCompare 接收兩個 Employee 對象,返回他們名字的比較。

在 main 方法中我創(chuàng)建了一個不同的 employee 的數(shù)組,并且將它連同一個方法引用表達(dá)式( Employee::myCompare )傳遞給了 Arrays.sort 方法。

等一下,如果我們看 Javadoc 你會發(fā)現(xiàn) sort 方法的第二個參數(shù)是 Comparator 類型的,但是我們卻傳遞了 Employee 的一個靜態(tài)方法引用。重要的問題就在這了,我既沒有讓 Employee 實現(xiàn) Comparable 接口,也沒有寫一個獨立的 Comparator 類,但是輸出確實沒有任何問題。

讓我們來看一看這是為什么。 Arrays.sort 方法期望一個 Comparator 的實例,而這個 Comparator 是一個 functional interface  ,這就意味著他只有一個方法,就是 compare 了。這里我們同樣惡意傳一個 Lambda 表達(dá)式,在這個表達(dá)式中提供 compare 方法的實現(xiàn)。但是在我們的里中,我們的 Employee 類已經(jīng)有了一個自己的比較方法。只是他們的名字是不一樣的,參數(shù)的類型、數(shù)量,返回值都是相同的,這里我們就可以創(chuàng)建一個方法引用,并將它傳遞給 sort 作為第二個參數(shù)。

當(dāng)有多個相同的名稱的方法的時候,編譯器會根據(jù)目標(biāo)類型選擇最佳的匹配。為了搞明白,來看一個例子:
 

public static int myCompare(Employee emp1, Employee emp2) {
 return emp1.name.compareTo(emp2.name);
}
//Another method with the same name as of the above.
public static int myCompare(Integer int1, Integer int2) {
 return int1.compareTo(int2);
}

我創(chuàng)建了兩個不同的數(shù)組,用作排序。
 

Employee[] employees = {new Employee("Nick"), new Employee("Robin"),
     new Employee("Josh"), new Employee("Andy"), new Employee("Mark")};
Integer[] ints = {1 , 4, 8, 2, 3, 8, 6};

現(xiàn)在,我執(zhí)行下面的兩行代碼
 

Arrays.sort(employees, Employee::myCompare);
Arrays.sort(ints, Employee::myCompare);

這里,兩行代碼中的方法引用聲明都是相同的(Employee::myCompare),唯一不同的是我們傳入的數(shù)組,我們不需要傳遞一個含糊不清的標(biāo)記用以知名那個方法作為方法引用,編譯器會幫助我們檢查第一個參數(shù),并且智能的找到合適的方法。
不要被靜態(tài)方法誤導(dǎo)了哦,我們還可以創(chuàng)建實例方法的引用。對于靜態(tài)方法我們使用類名::方法名來寫方法引用,如果是實例方法的引用,則是對象::方法名。

上面的例子已經(jīng)是相當(dāng)不錯的了,但是我們不必為整型的比較單獨寫一個方法,因為Integer已經(jīng)實現(xiàn)了Comparable并且提供了實現(xiàn)方法compareTo。所以我們直接使用下面這一行就行了:
 

Arrays.sort(ints, Integer::compareTo);

看到這里,你是否覺得有點迷惑?沒有?那我來讓你迷惑一下
這里, Integer 是一個類名(而不是一個像 new Integer() 一樣的實例),而 compareTo 方法卻是 Integer 類的成員方法(非靜態(tài)).如果你仔細(xì)看了我上面的描述就會知道,成員方法的方法引用::之前應(yīng)該是對象,但是為什么這里的語句確實合法的。
答案是:這種類型的語句允許使用在一些特定的類型中。Integer是一個數(shù)據(jù)類型,而對于數(shù)據(jù)類型來說,這種語句是允許的。
如果我們將 Employee 的方法 myCompare 變成非靜態(tài)的,然后這樣使用:Employee::myCompare,就會出編譯錯誤:No Suitable Method Found。

構(gòu)造方法引用
構(gòu)造方法引用被用作引用一個構(gòu)造方法而不實例化指定的類。
構(gòu)造方法引用是 JavaSE 8 的一個新的特性。我們可以構(gòu)造一個構(gòu)造方法的引用,并且將它作為參數(shù)傳遞給目標(biāo)類型。
當(dāng)我們使用方法引用的時候,我們引用一個已有的方法使用他們。同樣的,在使用構(gòu)造方法引用的時候,我們創(chuàng)建一個已有的構(gòu)造方法的引用。
上一節(jié)中我們已經(jīng)看到了構(gòu)造方法引用的語法類名::new,這看起來很像方法引用。這種構(gòu)造方法的引用可以分配給目標(biāo) functional interfaces 的實例。一個類可能有多個構(gòu)造方法,在這種情況下,編譯器會檢查 functional interfaces 的類型,最終找到最好的匹配。
對我來說寫出第一個構(gòu)造方法引用的程序有些困難,雖然我理解了他的語法,但是我卻不知道怎么使用它,以及它有什么用。最后,我花費了很久的努力,終于“啊,找到了...”,看看下面的程序吧。
 

public class ConstructorReference {
  public static void main(String[] ar){
    MyInterface in = MyClass::new;
    System.out.println("->"+in.getMeMyObject());
  }
}
interface MyInterface{
  MyClass getMeMyObject();
}
class MyClass{
  MyClass(){}
}

輸出是:
 

->com.MyClass@34e5307e

這看起來有點神奇是吧,這個接口和這個類除了接口中聲明的方法的返回值是 MyClass 類型的,沒有任何關(guān)系。

這個例子又激起了我心中的另一個問題:怎樣實例化一個帶參數(shù)的構(gòu)造方法引用?看看下面的程序:
 

public class ConstructorReference {
  public static void main(String[] ar){
    EmlpoyeeProvider provider = Employee::new;
    Employee emp = provider.getMeEmployee("John", 30);
    System.out.println("->Employee Name: "+emp.name);
    System.out.println("->Employee Age: "+emp.age);
  }
}
interface EmlpoyeeProvider{
  Employee getMeEmployee(String s, Integer i);
}
class Employee{
  String name;
  Integer age;
  Employee (String name, Integer age){
    this.name = name;
    this.age = age;
  }
}

輸出是:
 

->Employee Name: John
->Employee Age: 30

在看完這篇文章之前,讓我們再來看一看JavaSE8中的最酷的一個特性--默認(rèn)方法(Default Methods)

默認(rèn)方法(Default Methods)
JavaSE8 中將會引入一個叫做默認(rèn)方法的概念。早起的 Java 版本的接口擁有非常嚴(yán)格的接口,接口包含了一些抽象方法的聲明,所有非抽象的實現(xiàn)類必須要提供所有這些抽象方法的實現(xiàn),甚至是這些方法沒有用或者不合適出現(xiàn)在一些特殊的實現(xiàn)類中。在即將到來的Java 版本中,允許我們在接口中定義方法的默認(rèn)實現(xiàn)。廢話不多說,看下面:
 

public class DefaultMethods {
 public static void main(String[] ar){
 NormalInterface instance = new NormalInterfaceImpl();
 instance.myNormalMethod();
 instance.myDefaultMethod();
 }
}
interface NormalInterface{
 void myNormalMethod();
 void myDefaultMethod () default{
 System.out.println("-> myDefaultMethod");
 }
}
class NormalInterfaceImpl implements NormalInterface{
 @Override
 public void myNormalMethod() {
 System.out.println("-> myNormalMethod");
 }
}

輸出是:
 

-> myDefaultMethod

上面的接口中聲明了兩個方法,但是這個接口的實現(xiàn)類只實現(xiàn)了其中一個,因為 myDefaultMethod 使用 default 修飾符標(biāo)記了,而且提供了一個方法塊用作默認(rèn)實現(xiàn)。通用的重載規(guī)則在這里仍然生效。如果實現(xiàn)類實現(xiàn)了接口中的方法,調(diào)用的時候?qū)⑹钦{(diào)用類中的方法,否則,默認(rèn)實現(xiàn)將被調(diào)用。

集成父接口的接口可以增加、改變、移除父接口中的默認(rèn)實現(xiàn)。
 

interface ParentInterface{
 void initiallyNormal();
 void initiallyDefault () default{
 System.out.println("-> myDefaultMethod");
 }
}
interface ChildInterface extends ParentInterface{
 void initiallyNormal() default{
 System.out.println("now default - > initiallyNormal");
 }
 void initiallyDefault (); //Now a normal method
}

在這個例子中,ParentInterface  定義了兩個方法,一個是正常的,一個是有默認(rèn)實現(xiàn)的,子接口只是簡單的反了過來,給第一個方法添加了默認(rèn)實現(xiàn),給第二個方法移除了默認(rèn)實現(xiàn)。
設(shè)想一個類繼承了類 C ,實現(xiàn)了接口 I ,而且 C 有一個方法,而且跟I中的一個提供默認(rèn)方法的方法是重載兼容的。在這種情況下,C中的方法會優(yōu)先于I中的默認(rèn)方法,甚至C中的方法是抽象的時候,仍然是優(yōu)先的。
 

public class DefaultMethods {
 public static void main(String[] ar){
 Interfaxe impl = new NormalInterfaceImpl();
 impl.defaultMethod();
 }
}
class ParentClass{
 public void defaultMethod() {
 System.out.println("->ParentClass");
 }
}
interface Interfaxe{
 public void defaultMethod() default{
 System.out.println("->Interfaxe");
 }
}
class NormalInterfaceImpl extends ParentClass implements Interfaxe{}

輸出是:
 

->ParentClass

第二個例子是,我的類實現(xiàn)了兩個不同的接口,但是兩個接口中都提供了相同的具有默認(rèn)實現(xiàn)的方法的聲明。在這種情況下,編譯器將會搞不清楚怎么回事,實現(xiàn)類必須選擇兩個的其中一個實現(xiàn)。這可以通過如下的方式來使用 super 來搞定。
 

public class DefaultMethods {
 public static void main(String[] ar){
 FirstInterface impl = new NormalInterfaceImpl();
 impl.defaultMethod();
 }
}
interface FirstInterface{
 public void defaultMethod() default{
 System.out.println("->FirstInterface");
 }
}
interface SecondInterface{
 public void defaultMethod() default{
 System.out.println("->SecondInterface");
 }
}
class NormalInterfaceImpl implements FirstInterface, SecondInterface{
 public void defaultMethod(){
 SecondInterface.super.defaultMethod();
 }
}

輸出是:
 

->SecondInterface

現(xiàn)在,我們已經(jīng)看完了 Java  閉包的介紹。這個文章中,我們接觸到了 Functional Interfaces  和 Java Closure ,理解了 Java 的 Lambda 表達(dá)式,方法引用和構(gòu)造方法引用。而且我們也寫出了 Lambda 表達(dá)式的 Hello World 例子。
JavaSE8 很快就要到來了,我將很高興的擁抱這些新特性,也許這些新特性還是有些迷惑不清,但是我相信,隨著時間的推移,會變得越來越好。

相關(guān)文章

  • Java設(shè)計模式之接口隔離原則精解

    Java設(shè)計模式之接口隔離原則精解

    設(shè)計模式(Design pattern)代表了最佳的實踐,通常被有經(jīng)驗的面向?qū)ο蟮能浖_發(fā)人員所采用。設(shè)計模式是軟件開發(fā)人員在軟件開發(fā)過程中面臨的一般問題的解決方案。本篇介紹設(shè)計模式七大原則之一的接口隔離原則
    2022-02-02
  • Java服務(wù)限流算法的6種實現(xiàn)

    Java服務(wù)限流算法的6種實現(xiàn)

    服務(wù)限流是指通過控制請求的速率或次數(shù)來達(dá)到保護服務(wù)的目的,本文主要介紹了Java服務(wù)限流算法的6種實現(xiàn),具有一定的參考價值,感興趣的可以了解一下
    2023-05-05
  • java處理數(shù)據(jù)庫不支持的emoji表情符問題解決

    java處理數(shù)據(jù)庫不支持的emoji表情符問題解決

    這篇文章主要介紹了java處理數(shù)據(jù)庫不支持的emoji表情符問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-09-09
  • java正則表達(dá)式獲取指定HTML標(biāo)簽的指定屬性值且替換的方法

    java正則表達(dá)式獲取指定HTML標(biāo)簽的指定屬性值且替換的方法

    下面小編就為大家?guī)硪黄猨ava正則表達(dá)式獲取指定HTML標(biāo)簽的指定屬性值且替換的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • Java并發(fā)編程示例(三):線程中斷

    Java并發(fā)編程示例(三):線程中斷

    這篇文章主要介紹了Java并發(fā)編程示例(三):線程中斷,在本節(jié),我們所開發(fā)的示例程序?qū)?chuàng)建一個線程,五秒鐘后,利用中斷機制強制中止這個線程,需要的朋友可以參考下
    2014-12-12
  • springboot中redis正確的使用詳解

    springboot中redis正確的使用詳解

    本文主要介紹了springboot中redis正確的使用,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • JAVA裝飾者模式(從現(xiàn)實生活角度理解代碼原理)

    JAVA裝飾者模式(從現(xiàn)實生活角度理解代碼原理)

    裝飾者模式可以動態(tài)地給一個對象添加一些額外的職責(zé)。就增加功能來說,Decorator模式相比生成子類更為靈活。這篇文章主要介紹了JAVA裝飾者模式的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • Netty分布式高性能工具類recycler的使用及創(chuàng)建

    Netty分布式高性能工具類recycler的使用及創(chuàng)建

    這篇文章主要為大家介紹了Netty分布式高性能工具類recycler的使用和創(chuàng)建,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2022-03-03
  • 利用IDEA工具修改Maven多模塊項目標(biāo)識包名全過程記錄

    利用IDEA工具修改Maven多模塊項目標(biāo)識包名全過程記錄

    當(dāng)我們?yōu)榧追椒?wù)提供軟件開發(fā)服務(wù)時,需要按照甲方的要求去修改軟件的標(biāo)識,對于Maven項目來說就對應(yīng)著groupId,一般地寫對方公司的域名,如com.example,接下來通過本文給大家分享IDEA修改Maven多模塊項目標(biāo)識包名,感興趣的朋友一起看看吧
    2022-09-09
  • Spring中的@EnableScheduling定時任務(wù)注解

    Spring中的@EnableScheduling定時任務(wù)注解

    這篇文章主要介紹了Spring中的@EnableScheduling注解,@EnableScheduling是 Spring Framework 提供的一個注解,用于啟用 Spring 的定時任務(wù)功能,通過使用這個注解,可以在 Spring 應(yīng)用程序中創(chuàng)建定時任務(wù),需要的朋友可以參考下
    2024-01-01

最新評論