lambda是什么
“Lambda 表達式”(lambda expression)是一個匿名函數,Lambda表達式基於數學中的λ演算得名,直接對應於其中的lambda抽象(lambda abstraction),是一個匿名函數,即沒有函數名的函數。Lambda表達式可以表示閉包(注意和數學傳統意義上的不同)。
將一個變量傳入一個匿名函數然后對傳入函數進行操作。由於java中並沒有脫離類而存在的函數,所以通常獨立函數是以一個匿名內部類+一個方法構成的。lambda表達式代替的函數既沒有方法名也沒有訪問修飾符、明確的返回類型聲明。
實現解析
下面將解析下lambda與java的邏輯。
函數式變換最大的特點是:將一個函數(方法)賦值給一個變量。
函數式編程環境中比如javaScript
var fun = function(){
...
}
那么在Java中大概是這個樣子的。
var doSomthing = public void doSomthing(){
...
}
這個public 關鍵字是多余的,代碼就變成了這個樣子。
var doSomthing = void doSomthing(){
...
}
這個返回值類型可以依據內部return類型推導,所以返回值類型也不須要的。
var doSomthing = doSomthing(){
...
}
方法名在之前已經定義過了,代碼就變成了這個樣子。
var doSomthing = (){
...
}
由於這樣看起來怪怪的。所以使用->來定義方法參數和主體。()表示方法的參數列表,{}內部表示方法體。單行方法體可以省略{},強烈不建議這么做。
var doSomthing = ()->{
...
}
這就相當於一個代碼塊被賦值給了一個變量,這就是一個lambda表達式。
var這個關鍵字1.8版本的java中是沒有的。那么這個變量是什么呢。
在java1.8中所有的 lambda表達式本身就是某個接口的實現,所以var應該是某個接口。
下面定義一個接口
public interface MethodInterface {
void doSomething();
}
一個接口函數需要被實現的接口類型,我們叫它”函數式接口“。為了避免后來的人在這個接口中增加接口函數導致其有多個接口函數需要被實現,變成"非函數接口”,我們可以在這個上面加上一個聲明@FunctionalInterface, 這樣別人就無法在里面添加新的接口函數了。
@FunctionalInterface
public interface MethodInterface {
void doSomething();
}
函數式接口通常只有一個方法。
我們就可以直接把Lambda作為參數傳給函數, 而傳統的Java必須有明確的接口實現的定義。
那么上面的函數就成了
MethodInterface methodInterface = ()->{
...
}
那么我們將如何使用它呢.
methodInterface.doSomthing();
這么調用即可。
這個接口通用性很強並且定義起來太麻煩,我們是不是有其他辦法替換掉MethodInterface這個接口。
有的,在jdk1.8的java.util.function包中包含了大量定義好的接口。
接口名 | 參數 | 返回值 |
---|---|---|
Consumer<T> | T | void |
BiConsumer<T, U> | T,U | void |
BiConsumer<T, U, R> | T,U | R |
BooleanSupplier | 無 | Boolean |
DoubleBinaryOperator | Double,Double | Double |
以上列舉並不完全。
當然可以向上述文章那樣自定義接口方法類型但是需要@FunctionalInterface注解
實戰代碼
創建線程接口方式
接口
package java.lang;
@FunctionalInterface
public interface Runnable {
void run();
}
public class LambdaTest {
private static final int TOTAL = 5000;
private static AtomicInteger i = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
Executor executor = Executors.newCachedThreadPool();
CountDownLatch countDownLatch = new CountDownLatch(TOTAL);
for(int j=0;j<TOTAL;j++){
executor.execute(()->{
add();
countDownLatch.countDown();
});
}
countDownLatch.await();
System.out.println("求和的結果為:"+i);
}
private static void add(){
i.incrementAndGet();
}
}
總結
- 一個代碼塊被賦值給了一個變量。
- lambda表達式本身就是某個接口的實現。