[TOC]
# 第åä¸ç« 彿°å¼ç¼ç¨
> 彿°å¼ç¼ç¨è¯è¨æçºµä»£ç çæ®µå°±åæä½æ°æ®ä¸æ ·å®¹æã è½ç¶ Java 䏿¯å½æ°å¼è¯è¨ï¼ä½ Java 8 Lambda 表达å¼åæ¹æ³å¼ç¨ (Method References) å
è®¸ä½ ä»¥å½æ°å¼ç¼ç¨ã
å¨è®¡ç®æºæ¶ä»£æ©æï¼å
忝ç¨ç¼ºåæè´µçãå 乿¯ä¸ªäººé½ç¨æ±ç¼è¯è¨ç¼ç¨ã人们对ç¼è¯å¨ææäºè§£ï¼ä½ä»
ä»
æ³å°ç¼è¯çæç代ç è¯å®ä¼æ¯æå·¥ç¼ç å¤å¾å¤åèã
é常ï¼åªæ¯ä¸ºäºä½¿ç¨åºéåæéçå
åï¼ç¨åºåéè¿ä¿®æ¹å
åä¸çä»£ç æ¥èç代ç 空é´ï¼ä»¥ä¾¿å¨ç¨åºæ§è¡æ¶æ§è¡ä¸åçæä½ãè¿ç§ææ¯è¢«ç§°ä¸º**èªä¿®æ¹ä»£ç ** ï¼self-modifying codeï¼ãåªè¦ç¨åºè¶³å¤å°ï¼å°æ°äººå¯ä»¥ç»´æ¤æææ£æåç¥ç§çæ±ç¼ä»£ç ï¼ä½ å°±å¯ä»¥è®©å®è¿è¡èµ·æ¥ã
éçå
ååå¤çå¨å徿´ä¾¿å®ãæ´å¿«ãC è¯è¨åºç°å¹¶è¢«å¤§å¤æ°æ±ç¼ç¨åºå认为æ´âé«çº§âã人们åç°ä½¿ç¨ C å¯ä»¥æ¾èæé«ç产åãåæ¶ï¼ä½¿ç¨ C å建èªä¿®æ¹ä»£ç ä»ç¶ä¸é¾ã
éçç¡¬ä»¶è¶æ¥è¶ä¾¿å®ï¼ç¨åºçè§æ¨¡å夿æ§é½å¨å¢é¿ãè¿ä¸ååªæ¯è®©ç¨åºå·¥ä½åå¾å°é¾ãæä»¬æ³æ¹è®¾æ³ä½¿ä»£ç æ´å ä¸è´åææã使ç¨çº¯ç²¹çèªä¿®æ¹ä»£ç é æçç»æå°±æ¯ï¼æä»¬å¾é¾ç¡®å®ç¨åºå¨åä»ä¹ãå®ä¹é¾ä»¥æµè¯ï¼é¤éä½ æ³ä¸ç¹ç¹æµè¯è¾åºï¼ä»£ç 转æ¢åä¿®æ¹ççè¿ç¨ï¼
ç¶èï¼ä½¿ç¨ä»£ç 以æç§æ¹å¼æçºµå
¶ä»ä»£ç çæ³æ³ä¹å¾æè¶£ï¼åªè¦è½ä¿è¯å®æ´å®å
¨ãä»ä»£ç å建ï¼ç»´æ¤åå¯é æ§çè§åº¦æ¥çï¼è¿ä¸ªæ³æ³é常å¸å¼äººãæä»¬ä¸ç¨ä»å¤´å¼å§ç¼å大é代ç ï¼èæ¯ä»æäºçè§£ãå
åæµè¯åå¯é çç°æå°åå¼å§ï¼æåå°å®ä»¬ç»åå¨ä¸èµ·ä»¥å建æ°ä»£ç ãé¾éè¿ä¸ä¼è®©æä»¬æ´ææçï¼åæ¶åé æ´å¥å£®ç代ç åï¼
è¿å°±æ¯**彿°å¼ç¼ç¨**ï¼FPï¼çæä¹æå¨ãéè¿åå¹¶ç°æä»£ç æ¥çææ°åè½è䏿¯ä»å¤´å¼å§ç¼åææå
å®¹ï¼æä»¬å¯ä»¥æ´å¿«å°è·å¾æ´å¯é ç代ç ãè³å°å¨æäºæ
åµä¸ï¼è¿å¥ç论似ä¹å¾æç¨ãå¨è¿ä¸è¿ç¨ä¸ï¼ä¸äºé彿°å¼è¯è¨å·²ç»ä¹ æ¯äºä½¿ç¨å½æ°å¼ç¼ç¨äº§ççä¼é
çè¯æ³ã
ä½ ä¹å¯ä»¥è¿æ ·æ³ï¼
OOï¼object orientedï¼é¢åå¯¹è±¡ï¼æ¯æ½è±¡æ°æ®ï¼FPï¼functional programmingï¼å½æ°å¼ç¼ç¨ï¼æ¯æ½è±¡è¡ä¸ºã
纯粹ç彿°å¼è¯è¨å¨å®å
¨æ§æ¹é¢æ´è¿ä¸æ¥ãå®å¼ºå äºé¢å¤ç约æï¼å³æææ°æ®å¿
é¡»æ¯ä¸å¯åçï¼è®¾ç½®ä¸æ¬¡ï¼æ°¸ä¸æ¹åãå°å¼ä¼ éç»å½æ°ï¼è¯¥å½æ°ç¶åçææ°å¼ä½ä»ä¸ä¿®æ¹èªèº«å¤é¨çä»»ä½ä¸è¥¿ï¼å
æ¬å
¶åæ°æè¯¥å½æ°èå´ä¹å¤çå
ç´ ï¼ãå½å¼ºå¶æ§è¡æ¤æä½æ¶ï¼ä½ ç¥éä»»ä½é误é½ä¸æ¯ç±æè°çå¯ä½ç¨å¼èµ·çï¼å ä¸ºè¯¥å½æ°ä»
å建并è¿åç»æï¼è䏿¯å
¶ä»ä»»ä½é误ã
æ´å¥½çæ¯ï¼âä¸å¯åå¯¹è±¡åæ å¯ä½ç¨âèå¼è§£å³äºå¹¶åç¼ç¨ä¸æåºæ¬åææ£æçé®é¢ä¹ä¸ï¼å½ç¨åºçæäºé¨ååæ¶å¨å¤ä¸ªå¤çå¨ä¸è¿è¡æ¶ï¼ãè¿æ¯å¯åå
±äº«ç¶æçé®é¢ï¼è¿æå³ç代ç çä¸åé¨åï¼å¨ä¸åçå¤çå¨ä¸è¿è¡ï¼å¯ä»¥å°è¯åæ¶ä¿®æ¹åä¸åå
åï¼è°èµ¢äºï¼æ²¡äººç¥éï¼ã妿彿°æ°¸è¿ä¸ä¼ä¿®æ¹ç°æå¼ä½åªçææ°å¼ï¼åä¸ä¼å¯¹å
å产çäºç¨ï¼è¿æ¯çº¯å½æ°å¼è¯è¨çå®ä¹ã å æ¤ï¼ç»å¸¸æåºçº¯å½æ°å¼è¯è¨ä½ä¸ºå¹¶è¡ç¼ç¨çè§£å³æ¹æ¡ï¼è¿æå
¶ä»å¯è¡çè§£å³æ¹æ¡ï¼ã
éè¦æéå¤§å®¶çæ¯ï¼å½æ°å¼è¯è¨èåæå¾å¤å¨æºï¼è¿æå³çæè¿°å®ä»¬å¯è½ä¼æäºæ··æ·ãå®é常åå³äºåç§è§ç¹ï¼ä¸ºâå¹¶è¡ç¼ç¨âï¼â代ç å¯é æ§âåâ代ç å建ååºå¤ç¨âã[^1] å
³äºå½æ°å¼ç¼ç¨è½é«æå建æ´å¥å£®ç代ç è¿ä¸è§ç¹ä»åå¨é¨åäºè®®ãè½ç¶å·²æä¸äºå¥½çèä¾[^2]ï¼ä½è¿ä¸è¶³ä»¥è¯æçº¯å½æ°å¼è¯è¨å°±æ¯è§£å³ç¼ç¨é®é¢çæä½³æ¹æ³ã
FP ææ³å¼å¾èå
¥é FP è¯è¨ï¼å¦ PythonãJava 8 ä¹ä»ä¸å¸æ¶å¹¶æ¯æäº FPãæä»¬å°å¨æ¤ç« æ¢è®¨ã
## æ°æ§å¯¹æ¯
é常ï¼ä¼ éç»æ¹æ³çæ°æ®ä¸åï¼ç»æä¸åã妿æä»¬å¸ææ¹æ³å¨è°ç¨æ¶è¡ä¸ºä¸åï¼è¯¥æä¹åå¢ï¼ç»è®ºæ¯ï¼åªè¦è½å°ä»£ç ä¼ éç»æ¹æ³ï¼æä»¬å°±å¯ä»¥æ§å¶å®çè¡ä¸ºãæ¤åï¼æä»¬éè¿å¨æ¹æ³ä¸å建å
嫿éè¡ä¸ºç对象ï¼ç¶åå°è¯¥å¯¹è±¡ä¼ éç»æä»¬æ³è¦æ§å¶çæ¹æ³æ¥å®ææ¤æä½ãä¸é¢æä»¬ç¨ä¼ ç»å½¢å¼å Java 8 çæ¹æ³å¼ç¨ãLambda 表达å¼å嫿¼ç¤ºã代ç 示ä¾ï¼
```java
// functional/Strategize.java
interface Strategy {
String approach(String msg);
}
class Soft implements Strategy {
public String approach(String msg) {
return msg.toLowerCase() + "?";
}
}
class Unrelated {
static String twice(String msg) {
return msg + " " + msg;
}
}
public class Strategize {
Strategy strategy;
String msg;
Strategize(String msg) {
strategy = new Soft(); // [1]
this.msg = msg;
}
void communicate() {
System.out.println(strategy.approach(msg));
}
void changeStrategy(Strategy strategy) {
this.strategy = strategy;
}
public static void main(String[] args) {
Strategy[] strategies = {
new Strategy() { // [2]
public String approach(String msg) {
return msg.toUpperCase() + "!";
}
},
msg -> msg.substring(0, 5), // [3]
Unrelated::twice // [4]
};
Strategize s = new Strategize("Hello there");
s.communicate();
for(Strategy newStrategy : strategies) {
s.changeStrategy(newStrategy); // [5]
s.communicate(); // [6]
}
}
}
```
è¾åºç»æ:
```
hello there?
HELLO THERE!
Hello
Hello there Hello there
```
**Strategy** æ¥å£æä¾äºåä¸ç `approach()` æ¹æ³æ¥æ¿è½½å½æ°å¼åè½ãéè¿å建ä¸åç **Strategy** å¯¹è±¡ï¼æä»¬å¯ä»¥å建ä¸åçè¡ä¸ºã
ä¼ ç»ä¸ï¼æä»¬éè¿å建ä¸ä¸ªå®ç° **Strategy** æ¥å£çç±»æ¥å®ç°æ¤è¡ä¸ºï¼æ¯å¦å¨ **Soft**ã
- **[1]** å¨ **Strategize** ä¸ï¼**Soft** ä½ä¸ºé»è®¤çç¥ï¼å¨æé 彿°ä¸èµå¼ã
- **[2]** ä¸ç§ç¥æ¾ç®ç䏿´èªåçæ¹æ³æ¯å建ä¸ä¸ª**å¿åå
é¨ç±»**ãå³ä½¿è¿æ ·ï¼ä»æç¸å½æ°éçåä½ä»£ç ãä½ æ»æ¯è¦ä»ç»è§å¯ï¼âå¦ï¼åæ¥è¿æ ·ï¼è¿é使ç¨äºå¿åå
é¨ç±»ãâ
- **[3]** Java 8 ç Lambda 表达å¼ãç±ç®å¤´ `->` åéå¼åæ°å彿°ä½ï¼ç®å¤´å·¦è¾¹æ¯åæ°ï¼ç®å¤´å³ä¾§æ¯ä» Lambda è¿åç表达å¼ï¼å³å½æ°ä½ãè¿å®ç°äºä¸å®ä¹ç±»ãå¿åå
é¨ç±»ç¸åçææï¼ä½ä»£ç å°å¾å¤ã
- **[4]** Java 8 ç**æ¹æ³å¼ç¨**ï¼ç± `::` åºåãå¨ `::` ç左边æ¯ç±»æå¯¹è±¡çåç§°ï¼å¨ `::` çå³è¾¹æ¯æ¹æ³çåç§°ï¼ä½æ²¡æåæ°å表ã
- **[5]** å¨ä½¿ç¨é»è®¤ç **Soft** **strategy** ä¹åï¼æä»¬éæ¥éåæ°ç»ä¸çææ **Strategy**ï¼å¹¶ä½¿ç¨ `changeStrategy()` æ¹æ³å°æ¯ä¸ª **Strategy** æ¾å
¥ åé `s` ä¸ã
- **[6]** ç°å¨ï¼æ¯æ¬¡è°ç¨ `communicate()` é½ä¼äº§çä¸åçè¡ä¸ºï¼å
·ä½åå³äºæ¤å»æ£å¨ä½¿ç¨ççç¥**代ç 对象**ãæä»¬ä¼ éçæ¯è¡ä¸ºï¼èéä»
æ°æ®ã[^3]
å¨ Java 8 ä¹åï¼æä»¬è½å¤éè¿ **[1]** å **[2]** çæ¹å¼ä¼ éåè½ãç¶èï¼è¿ç§è¯æ³ç读åé常笨æï¼å¹¶ä¸æä»¬å«æ éæ©ãæ¹æ³å¼ç¨å Lambda 表达å¼çåºç°è®©æä»¬å¯ä»¥å¨éè¦æ¶**ä¼ éåè½**ï¼è䏿¯ä»
å¨å¿
è¦æè¿ä¹åã
## Lambda表达å¼
Lambda è¡¨è¾¾å¼æ¯ä½¿ç¨**æå°å¯è½**è¯æ³ç¼åç彿°å®ä¹ï¼
1. Lambda 表达å¼äº§ç彿°ï¼è䏿¯ç±»ã å¨ JVMï¼Java Virtual Machineï¼Java èææºï¼ä¸ï¼ä¸å齿¯ä¸ä¸ªç±»ï¼å æ¤å¨å¹åæ§è¡åç§æä½ä½¿ Lambda çèµ·æ¥å彿° ââ ä½ä½ä¸ºç¨åºåï¼ä½ å¯ä»¥é«å
´å°åè£
å®ä»¬âåªæ¯å½æ°âã
2. Lambda è¯æ³å°½å¯è½å°ï¼è¿æ£æ¯ä¸ºäºä½¿ Lambda æäºç¼åå使ç¨ã
æä»¬å¨ **Strategize.java** ä¸çå°äºä¸ä¸ª Lambda 表达å¼ï¼ä½è¿æå
¶ä»è¯æ³åä½ï¼
```java
// functional/LambdaExpressions.java
interface Description {
String brief();
}
interface Body {
String detailed(String head);
}
interface Multi {
String twoArg(String head, Double d);
}
public class LambdaExpressions {
static Body bod = h -> h + " No Parens!"; // [1]
static Body bod2 = (h) -> h + " More details"; // [2]
static Description desc = () -> "Short info"; // [3]
static Multi mult = (h, n) -> h + n; // [4]
static Description moreLines = () -> { // [5]
System.out.println("moreLines()");
return "from moreLines()";
};
public static void main(String[] args) {
System.out.println(bod.detailed("Oh!"));
System.out.println(bod2.detailed("Hi!"));
System.out.println(desc.brief());
System.out.println(mult.twoArg("Pi! ", 3.14159));
System.out.println(moreLines.brief());
}
}
```
è¾åºç»æï¼
```
Oh! No Parens!
Hi! More details
Short info
Pi! 3.14159
moreLines()
from moreLines()
```
æä»¬ä»ä¸ä¸ªæ¥å£å¼å§ï¼æ¯ä¸ªæ¥å£é½æä¸ä¸ªåç¬çæ¹æ³ï¼å¾å¿«å°±ä¼çè§£å®çéè¦æ§ï¼ã使¯ï¼æ¯ä¸ªæ¹æ³é½æä¸åæ°éçåæ°ï¼ä»¥ä¾¿æ¼ç¤º Lambda 表达å¼è¯æ³ã
ä»»ä½ Lambda 表达å¼çåºæ¬è¯æ³æ¯ï¼
1. åæ°ã
2. æ¥ç `->`ï¼å¯è§ä¸ºâ产åºâã
3. `->` ä¹åçå
容齿¯æ¹æ³ä½ã
- **[1]** å½åªç¨ä¸ä¸ªåæ°ï¼å¯ä»¥ä¸éè¦æ¬å· `()`ã ç¶èï¼è¿æ¯ä¸ä¸ªç¹ä¾ã
- **[2]** æ£å¸¸æ
åµä½¿ç¨æ¬å· `()` å
è£¹åæ°ã 为äºä¿æä¸è´æ§ï¼ä¹å¯ä»¥ä½¿ç¨æ¬å· `()` å
裹åä¸ªåæ°ï¼è½ç¶è¿ç§æ
åµå¹¶ä¸å¸¸è§ã
- **[3]** å¦ææ²¡æåæ°ï¼åå¿
é¡»ä½¿ç¨æ¬å· `()` è¡¨ç¤ºç©ºåæ°å表ã
- **[4]** 对äºå¤ä¸ªåæ°ï¼å°åæ°å表æ¾å¨æ¬å· `()` ä¸ã
å°ç®å为æ¢ï¼ææ Lambda è¡¨è¾¾å¼æ¹æ³ä½é½æ¯åè¡ã 该表达å¼çç»æèªå¨æä¸º Lambda 表达å¼çè¿åå¼ï¼å¨æ¤å¤ä½¿ç¨ **return** å
³é®åæ¯éæ³çã è¿æ¯ Lambda 表达å¼ç¼©åç¨äºæè¿°åè½çè¯æ³çå¦ä¸ç§æ¹å¼ã
**[5]** å¦æå¨ Lambda 表达å¼ä¸ç¡®å®éè¦å¤è¡ï¼åå¿
é¡»å°è¿äºè¡æ¾å¨è±æ¬å·ä¸ã å¨è¿ç§æ
åµä¸ï¼å°±éè¦ä½¿ç¨ **return**ã
Lambda 表达å¼é常æ¯**å¿åå
é¨ç±»**äº§çæ´æè¯»ç代ç ï¼å æ¤æä»¬å°å¨æ¬ä¹¦ä¸å°½å¯è½ä½¿ç¨å®ä»¬ã
### éå½
éå½å½æ°æ¯ä¸ä¸ªèªæè°ç¨ç彿°ãå¯ä»¥ç¼åéå½ç Lambda 表达å¼ï¼ä½éè¦æ³¨æï¼é彿¹æ³å¿
é¡»æ¯å®ä¾åéæéæåéï¼å¦åä¼åºç°ç¼è¯æ¶éè¯¯ã æä»¬å°ä¸ºæ¯ä¸ªæ¡ä¾å建ä¸ä¸ªç¤ºä¾ã
è¿ä¸¤ä¸ªç¤ºä¾é½éè¦ä¸ä¸ªæ¥å **int** ååæ°å¹¶çæ **int** çæ¥å£ï¼
```java
// functional/IntCall.java
interface IntCall {
int call(int arg);
}
```
æ´æ° n çé¶ä¹å°ææå°äºæçäº n çæ£æ´æ°ç¸ä¹ã é¶ä¹å½æ°æ¯ä¸ä¸ªå¸¸è§çéå½ç¤ºä¾ï¼
```java
// functional/RecursiveFactorial.java
public class RecursiveFactorial {
static IntCall fact;
public static void main(String[] args) {
fact = n -> n == 0 ? 1 : n * fact.call(n - 1);
for(int i = 0; i <= 10; i++)
System.out.println(fact.call(i));
}
}
```
è¾åºç»æï¼
```
1
1
2
6
24
120
720
5040
40320
362880
3628800
```
è¿éï¼`fact` æ¯ä¸ä¸ªéæåéã æ³¨æä½¿ç¨ä¸å
**if-else**ã éå½å½æ°å°ä¸ç´è°ç¨èªå·±ï¼ç´å° `i == 0`ãææéå½å½æ°é½æâ忢æ¡ä»¶âï¼å¦åå°æ ééå½å¹¶äº§çå¼å¸¸ã
æä»¬å¯ä»¥å° `Fibonacci` åºåæ¹ä¸ºä½¿ç¨éå½ Lambda è¡¨è¾¾å¼æ¥å®ç°ï¼è¿æ¬¡ä½¿ç¨å®ä¾åéï¼
```java
// functional/RecursiveFibonacci.java
public class RecursiveFibonacci {
IntCall fib;
RecursiveFibonacci() {
fib = n -> n == 0 ? 0 :
n == 1 ? 1 :
fib.call(n - 1) + fib.call(n - 2);
}
int fibonacci(int n) { return fib.call(n); }
public static void main(String[] args) {
RecursiveFibonacci rf = new RecursiveFibonacci();
for(int i = 0; i <= 10; i++)
System.out.println(rf.fibonacci(i));
}
}
```
è¾åºç»æï¼
```
0
1
1
2
3
5
8
13
21
34
55
```
å° `Fibonacci` åºåä¸çæå两个å
ç´ æ±åæ¥äº§çä¸ä¸ä¸ªå
ç´ ã
## æ¹æ³å¼ç¨
Java 8 æ¹æ³å¼ç¨æ²¡æåå²å
è¢±ãæ¹æ³å¼ç¨ç»æï¼ç±»åæå¯¹è±¡åï¼åé¢è· `::` [^4]ï¼ç¶åè·æ¹æ³åç§°ã
```java
// functional/MethodReferences.java
import java.util.*;
interface Callable { // [1]
void call(String s);
}
class Describe {
void show(String msg) { // [2]
System.out.println(msg);
}
}
public class MethodReferences {
static void hello(String name) { // [3]
System.out.println("Hello, " + name);
}
static class Description {
String about;
Description(String desc) { about = desc; }
void help(String msg) { // [4]
System.out.println(about + " " + msg);
}
}
static class Helper {
static void assist(String msg) { // [5]
System.out.println(msg);
}
}
public static void main(String[] args) {
Describe d = new Describe();
Callable c = d::show; // [6]
c.call("call()"); // [7]
c = MethodReferences::hello; // [8]
c.call("Bob");
c = new Description("valuable")::help; // [9]
c.call("information");
c = Helper::assist; // [10]
c.call("Help!");
}
}
```
è¾åºç»æï¼
```
call()
Hello, Bob
valuable information
Help!
```
**[1]** æä»¬ä»å䏿¹æ³æ¥å£å¼å§ï¼åæ ·ï¼ä½ å¾å¿«å°±ä¼äºè§£å°è¿ä¸ç¹çéè¦æ§ï¼ã
**[2]** `show()` çç¾åï¼åæ°ç±»ååè¿åç±»åï¼ç¬¦å **Callable** ç `call()` çç¾åã
**[3]** `hello()` ä¹ç¬¦å `call()` çç¾åã
**[4]** `help()` ä¹ç¬¦åï¼å®æ¯éæå
é¨ç±»ä¸çééææ¹æ³ã
**[5]** `assist()` æ¯éæå
é¨ç±»ä¸çéææ¹æ³ã
**[6]** æä»¬å° **Describe** å¯¹è±¡çæ¹æ³å¼ç¨èµå¼ç» **Callable** ï¼å®æ²¡æ `show()` æ¹æ³ï¼èæ¯ `call()` æ¹æ³ã 使¯ï¼Java 似乿¥åç¨è¿ä¸ªç似奿ªçèµå¼ï¼å ä¸ºæ¹æ³å¼ç¨ç¬¦å **Callable** ç `call()` æ¹æ³çç¾åã
**[7]** æä»¬ç°å¨å¯ä»¥éè¿è°ç¨ `call()` æ¥è°ç¨ `show()`ï¼å 为 Java å° `call()` æ å°å° `show()`ã
**[8]** è¿æ¯ä¸ä¸ª**éæ**æ¹æ³å¼ç¨ã
**[9]** è¿æ¯ **[6]** çå¦ä¸ä¸ªçæ¬ï¼å¯¹å·²å®ä¾åå¯¹è±¡çæ¹æ³çå¼ç¨ï¼ææ¶ç§°ä¸º*ç»å®æ¹æ³å¼ç¨*ã
**[10]** æåï¼è·åéæå
é¨ç±»çæ¹æ³å¼ç¨çæä½ä¸ **[8]** ä¸å¤é¨ç±»æ¹å¼ä¸æ ·ã
ä¸ä¾åªæ¯ç®ççä»ç»ï¼æä»¬å¾å¿«å°±è½çå°æ¹æ³å¼ç¨çå
¨é¨ååã
### Runnableæ¥å£
**Runnable** æ¥å£èª 1.0 ç以æ¥ä¸ç´å¨ Java ä¸ï¼å æ¤ä¸éè¦å¯¼å
¥ãå®ä¹ç¬¦åç¹æ®çåæ¹æ³æ¥å£æ ¼å¼ï¼å®çæ¹æ³ `run()` ä¸å¸¦åæ°ï¼ä¹æ²¡æè¿åå¼ãå æ¤ï¼æä»¬å¯ä»¥ä½¿ç¨ Lambda 表达å¼åæ¹æ³å¼ç¨ä½ä¸º **Runnable**ï¼
```java
// functional/RunnableMethodReference.java
// æ¹æ³å¼ç¨ä¸ Runnable æ¥å£çç»å使ç¨
class Go {
static void go() {
System.out.println("Go::go()");
}
}
public class RunnableMethodReference {
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
System.out.println("Anonymous");
}
}).start();
new Thread(
() -> System.out.println("lambda")
).start();
new Thread(Go::go).start();
}
}
```
è¾åºç»æï¼
```
Anonymous
lambda
Go::go()
```
**Thread** å¯¹è±¡å° **Runnable** ä½ä¸ºå
¶æé 彿°åæ°ï¼å¹¶å
·æä¼è°ç¨ `run()` çæ¹æ³ `start()`ã **注æ**ï¼åªæ**å¿åå
é¨ç±»**æéè¦å
·æå为 `run()` çæ¹æ³ã
### æªç»å®çæ¹æ³å¼ç¨
æªç»å®çæ¹æ³å¼ç¨æ¯ææ²¡æå
³èå¯¹è±¡çæ®éï¼ééæï¼æ¹æ³ã ä½¿ç¨æªç»å®çå¼ç¨ä¹åï¼æä»¬å¿
é¡»å
æä¾å¯¹è±¡ï¼
```java
// functional/UnboundMethodReference.java
// æ²¡ææ¹æ³å¼ç¨ç对象
class X {
String f() { return "X::f()"; }
}
interface MakeString {
String make();
}
interface TransformX {
String transform(X x);
}
public class UnboundMethodReference {
public static void main(String[] args) {
// MakeString ms = X::f; // [1]
TransformX sp = X::f;
X x = new X();
System.out.println(sp.transform(x)); // [2]
System.out.println(x.f()); // åçææ
}
}
```
è¾åºç»æï¼
```
X::f()
X::f()
```
æªæ¢ç®åï¼æä»¬å·²ç»ç¥éäºä¸æ¥å£æ¹æ³ååçæ¹æ³å¼ç¨ã å¨ **[1]**ï¼æä»¬å°è¯æ `X` ç `f()` æ¹æ³å¼ç¨èµå¼ç» **MakeString**ãç»æï¼å³ä½¿ `make()` ä¸ `f()` å
·æç¸åçç¾åï¼ç¼è¯ä¹ä¼æ¥âinvalid method referenceâï¼æ ææ¹æ³å¼ç¨ï¼é误ã è¿æ¯å 为å®é
ä¸è¿æå¦ä¸ä¸ªéèçåæ°ï¼æä»¬çèæå `this`ã ä½ ä¸è½å¨æ²¡æ `X` 对象çåæä¸è°ç¨ `f()`ã å æ¤ï¼`X :: f` 表示æªç»å®çæ¹æ³å¼ç¨ï¼å 为å®å°æªâç»å®âå°å¯¹è±¡ã
è¦è§£å³è¿ä¸ªé®é¢ï¼æä»¬éè¦ä¸ä¸ª `X` å¯¹è±¡ï¼æä»¥æä»¬çæ¥å£å®é
ä¸éè¦ä¸ä¸ªé¢å¤çåæ°çæ¥å£ï¼å¦ä¸ä¾ä¸ç **TransformX**ã å¦æå° `X :: f` èµå¼ç» **TransformX**ï¼è¿å¨ Java 䏿¯å
许çãè¿æ¬¡æä»¬éè¦è°æ´ä¸å¿é颿ââä½¿ç¨æªç»å®çå¼ç¨æ¶ï¼å½æ°æ¹æ³çç¾åï¼æ¥å£ä¸çåä¸ªæ¹æ³ï¼ä¸å䏿¹æ³å¼ç¨çç¾åå®å
¨å¹é
ã çç±æ¯ï¼ä½ éè¦ä¸ä¸ªå¯¹è±¡æ¥è°ç¨æ¹æ³ã
**[2]** çç»ææç¹åèçæ¥è½¬å¼¯ã ææ¥åæªç»å®çå¼ç¨å¹¶å¯¹å
¶è°ç¨ `transform()`ï¼å°å
¶ä¼ éç» `X`ï¼å¹¶ä»¥æç§æ¹å¼å¯¼è´å¯¹ `x.f()` çè°ç¨ã Java ç¥éå®å¿
é¡»éç¨ç¬¬ä¸ä¸ªåæ°ï¼è¿å®é
ä¸å°±æ¯ `this`ï¼å¹¶å¨å
¶ä¸è°ç¨æ¹æ³ã
```java
// functional/MultiUnbound.java
// æªç»å®çæ¹æ³ä¸å¤åæ°çç»åè¿ç¨
class This {
void two(int i, double d) {}
void three(int i, double d, String s) {}
void four(int i, double d, String s, char c) {}
}
interface TwoArgs {
void call2(This athis, int i, double d);
}
interface ThreeArgs {
void call3(This athis, int i, double d, String s);
}
interface FourArgs {
void call4(
This athis, int i, double d, String s, char c);
}
public class MultiUnbound {
public static void main(String[] args) {
TwoArgs twoargs = This::two;
ThreeArgs threeargs = This::three;
FourArgs fourargs = This::four;
This athis = new This();
twoargs.call2(athis, 11, 3.14);
threeargs.call3(athis, 11, 3.14, "Three");
fourargs.call4(athis, 11, 3.14, "Four", 'Z');
}
}
```
为äºè¯´æè¿ä¸ç¹ï¼æå°ç±»å½å为 **This** ï¼å½æ°æ¹æ³ç第ä¸ä¸ªåæ°åæ¯ **athis**ï¼ä½æ¯ä½ åºè¯¥éæ©å
¶ä»åç§°ä»¥é²æ¢çäº§ä»£ç æ··æ·ã
### æé 彿°å¼ç¨
ä½ è¿å¯ä»¥æè·æé 彿°çå¼ç¨ï¼ç¶åéè¿å¼ç¨è°ç¨è¯¥æé 彿°ã
```java
// functional/CtorReference.java
class Dog {
String name;
int age = -1; // For "unknown"
Dog() { name = "stray"; }
Dog(String nm) { name = nm; }
Dog(String nm, int yrs) { name = nm; age = yrs; }
}
interface MakeNoArgs {
Dog make();
}
interface Make1Arg {
Dog make(String nm);
}
interface Make2Args {
Dog make(String nm, int age);
}
public class CtorReference {
public static void main(String[] args) {
MakeNoArgs mna = Dog::new; // [1]
Make1Arg m1a = Dog::new; // [2]
Make2Args m2a = Dog::new; // [3]
Dog dn = mna.make();
Dog d1 = m1a.make("Comet");
Dog d2 = m2a.make("Ralph", 4);
}
}
```
**Dog** æä¸ä¸ªæé 彿°ï¼å½æ°æ¥å£å
ç `make()` æ¹æ³åæ äºæé 彿°åæ°åè¡¨ï¼ `make()` æ¹æ³åç§°å¯ä»¥ä¸åï¼ã
**注æ**æä»¬å¦ä½å¯¹ **[1]**ï¼**[2]** å **[3]** ä¸çæ¯ä¸ä¸ªä½¿ç¨ `Dog :: new`ã è¿ 3 个æé 彿°åªæä¸ä¸ªç¸ååç§°ï¼`:: new`ï¼ä½å¨æ¯ç§æ
åµä¸é½èµå¼ç»ä¸åçæ¥å£ãç¼è¯å¨å¯ä»¥æ£æµå¹¶ç¥éä»åªä¸ªæé 彿°å¼ç¨ã
ç¼è¯å¨è½è¯å«å¹¶è°ç¨ä½ çæé 彿°ï¼ 卿¬ä¾ä¸ä¸º `make()`ï¼ã
## 彿°å¼æ¥å£
æ¹æ³å¼ç¨å Lambda 表达å¼å¿
须被èµå¼ï¼åæ¶ç¼è¯å¨éè¦è¯å«ç±»åä¿¡æ¯ä»¥ç¡®ä¿ç±»åæ£ç¡®ã Lambda 表达å¼ç¹å«å¼å
¥äºæ°çè¦æ±ã 代ç 示ä¾ï¼
```java
x -> x.toString()
```
æä»¬æ¸
æ¥è¿éè¿åç±»åå¿
é¡»æ¯ **String**ï¼ä½ `x` æ¯ä»ä¹ç±»åå¢ï¼
Lambda 表达å¼å
å«ç±»åæ¨å¯¼ï¼ç¼è¯å¨ä¼èªå¨æ¨å¯¼åºç±»åä¿¡æ¯ï¼é¿å
äºç¨åºåæ¾å¼å°å£°æï¼ãç¼è¯å¨å¿
é¡»è½å¤ä»¥æç§æ¹å¼æ¨å¯¼åº `x` çç±»åã
ä¸é¢æ¯ç¬¬ 2 个代ç 示ä¾ï¼
```java
(x, y) -> x + y
```
ç°å¨ `x` å `y` å¯ä»¥æ¯ä»»ä½æ¯æ `+` è¿ç®ç¬¦è¿æ¥çæ°æ®ç±»åï¼å¯ä»¥æ¯ä¸¤ä¸ªä¸åçæ°å¼ç±»åæè
æ¯ 1 个 **String** å ä»»æä¸ç§å¯èªå¨è½¬æ¢ä¸º **String** çæ°æ®ç±»åï¼è¿å
æ¬äºå¤§å¤æ°ç±»åï¼ã 使¯ï¼å½ Lambda 表达å¼è¢«èµå¼æ¶ï¼ç¼è¯å¨å¿
é¡»ç¡®å® `x` å `y` çç¡®åç±»åä»¥çææ£ç¡®ç代ç ã
该é®é¢ä¹éç¨äºæ¹æ³å¼ç¨ã åè®¾ä½ è¦ä¼ é `System.out :: println` å°ä½ æ£å¨ç¼åçæ¹æ³ ï¼ä½ æä¹ç¥éä¼ éç»æ¹æ³çåæ°çç±»åï¼
为äºè§£å³è¿ä¸ªé®é¢ï¼Java 8 å¼å
¥äº `java.util.function` å
ãå®å
å«ä¸ç»æ¥å£ï¼è¿äºæ¥å£æ¯ Lambda 表达å¼åæ¹æ³å¼ç¨çç®æ ç±»åã æ¯ä¸ªæ¥å£åªå
å«ä¸ä¸ªæ½è±¡æ¹æ³ï¼ç§°ä¸ºå½æ°å¼æ¹æ³ã
å¨ç¼åæ¥å£æ¶ï¼å¯ä»¥ä½¿ç¨ `@FunctionalInterface` æ³¨è§£å¼ºå¶æ§è¡æ¤â彿°å¼æ¹æ³â模å¼ï¼
```java
// functional/FunctionalAnnotation.java
@FunctionalInterface
interface Functional {
String goodbye(String arg);
}
interface FunctionalNoAnn {
String goodbye(String arg);
}
/*
@FunctionalInterface
interface NotFunctional {
String goodbye(String arg);
String hello(String arg);
}
产çé误信æ¯:
NotFunctional is not a functional interface
multiple non-overriding abstract methods
found in interface NotFunctional
*/
public class FunctionalAnnotation {
public String goodbye(String arg) {
return "Goodbye, " + arg;
}
public static void main(String[] args) {
FunctionalAnnotation fa =
new FunctionalAnnotation();
Functional f = fa::goodbye;
FunctionalNoAnn fna = fa::goodbye;
// Functional fac = fa; // Incompatible
Functional fl = a -> "Goodbye, " + a;
FunctionalNoAnn fnal = a -> "Goodbye, " + a;
}
}
```
`@FunctionalInterface` 注解æ¯å¯éç; Java å¨ `main()` 䏿 **Functional** å **FunctionalNoAnn** é½å½ä½å½æ°å¼æ¥å£ã `@FunctionalInterface` çå¼å¨ `NotFunctional` çå®ä¹ä¸å¯è§ï¼æ¥å£ä¸å¦ææå¤ä¸ªæ¹æ³åä¼äº§çç¼è¯æ¶éè¯¯æ¶æ¯ã
ä»ç»è§å¯å¨å®ä¹ `f` å `fna` æ¶åçäºä»ä¹ã `Functional` å `FunctionalNoAnn` å®ä¹æ¥å£ï¼ç¶è被èµå¼çåªæ¯æ¹æ³ `goodbye()`ãé¦å
ï¼è¿åªæ¯ä¸ä¸ªæ¹æ³è䏿¯ç±»ï¼å
¶æ¬¡ï¼å®çè³é½ä¸æ¯å®ç°äºè¯¥æ¥å£çç±»ä¸çæ¹æ³ãJava 8 å¨è¿éæ·»å äºä¸ç¹å°éæ³ï¼å¦æå°æ¹æ³å¼ç¨æ Lambda 表达å¼èµå¼ç»å½æ°å¼æ¥å£ï¼ç±»åéè¦å¹é
ï¼ï¼Java ä¼éé
ä½ çèµå¼å°ç®æ æ¥å£ã ç¼è¯å¨ä¼èªå¨å
è£
æ¹æ³å¼ç¨æ Lambda 表达å¼å°å®ç°ç®æ æ¥å£çç±»çå®ä¾ä¸ã
尽管 `FunctionalAnnotation` ç¡®å®éå `Functional` 模åï¼ä½ Java ä¸å
许æä»¬å° `FunctionalAnnotation` å `fac` å®ä¹ä¸æ ·ç´æ¥èµå¼ç» `Functional`ï¼å ä¸ºå®æ²¡ææç¡®å°å®ç° `Functional` æ¥å£ã 令人æå¥çæ¯ ï¼Java 8 å
许æä»¬ä»¥ç®ä¾¿çè¯æ³ä¸ºæ¥å£èµå¼å½æ°ã
`java.util.function` å
æ¨å¨å建ä¸ç»å®æ´çç®æ æ¥å£ï¼ä½¿å¾æä»¬ä¸è¬æ
åµä¸ä¸éåå®ä¹èªå·±çæ¥å£ãè¿ä¸»è¦æ¯å ä¸ºåºæ¬ç±»åä¼äº§çä¸å°é¨åæ¥å£ã å¦æä½ äºè§£å½å模å¼ï¼é¡¾åæä¹å°±è½ç¥éç¹å®æ¥å£çä½ç¨ã
以䏿¯åºæ¬å½åååï¼
1. 妿åªå¤ç对象èéåºæ¬ç±»åï¼åç§°å为 `Function`ï¼`Consumer`ï¼`Predicate` çãåæ°ç±»åéè¿æ³åæ·»å ã
2. å¦ææ¥æ¶çåæ°æ¯åºæ¬ç±»åï¼åç±åç§°ç第ä¸é¨å表示ï¼å¦ `LongConsumer`ï¼`DoubleFunction`ï¼`IntPredicate` çï¼ä½åºæ¬ `Supplier` ç±»åä¾å¤ã
3. 妿è¿åå¼ä¸ºåºæ¬ç±»åï¼åç¨ `To` 表示ï¼å¦ `ToLongFunction ` å `IntToLongFunction`ã
4. 妿è¿åå¼ç±»åä¸åæ°ç±»åä¸è´ï¼åæ¯ä¸ä¸ªè¿ç®ç¬¦ï¼åä¸ªåæ°ä½¿ç¨ `UnaryOperator`ï¼ä¸¤ä¸ªåæ°ä½¿ç¨ `BinaryOperator`ã
5. å¦ææ¥æ¶ä¸¤ä¸ªåæ°ä¸è¿åå¼ä¸ºå¸å°å¼ï¼åæ¯ä¸ä¸ªè°è¯ï¼Predicateï¼ã
6. å¦ææ¥æ¶çä¸¤ä¸ªåæ°ç±»åä¸åï¼ååç§°ä¸æä¸ä¸ª `Bi`ã
ä¸è¡¨æè¿°äº `java.util.function` ä¸çç®æ ç±»åï¼å
æ¬ä¾å¤æ
åµï¼ï¼
| **ç¹å¾** |**彿°å¼æ¹æ³å**|**示ä¾**|
| :---- | :----: | :----: |
|æ åæ°ï¼
æ è¿åå¼|**Runnable**
(java.lang)
`run()`|**Runnable**|
|æ åæ°ï¼
è¿åç±»åä»»æ|**Supplier**
`get()`
`getAsç±»å()`| **Supplier``
BooleanSupplier
IntSupplier
LongSupplier
DoubleSupplier**|
|æ åæ°ï¼
è¿åç±»åä»»æ|**Callable**
(java.util.concurrent)
`call()`|**Callable``**|
|1 åæ°ï¼
æ è¿åå¼|**Consumer**
`accept()`|**`Consumer`
IntConsumer
LongConsumer
DoubleConsumer**|
|2 åæ° **Consumer**|**BiConsumer**
`accept()`|**`BiConsumer`**|
|2 åæ° **Consumer**ï¼
1 å¼ç¨ï¼
1 åºæ¬ç±»å|**Objç±»åConsumer**
`accept()`|**`ObjIntConsumer`
`ObjLongConsumer`
`ObjDoubleConsumer`**|
|1 åæ°ï¼
è¿åç±»åä¸å|**Function**
`apply()`
**Toç±»å** å **ç±»åToç±»å**
`applyAsç±»å()`|**Function``
IntFunction``
`LongFunction`
DoubleFunction``
ToIntFunction``
`ToLongFunction`
`ToDoubleFunction`
IntToLongFunction
IntToDoubleFunction
LongToIntFunction
LongToDoubleFunction
DoubleToIntFunction
DoubleToLongFunction**|
|1 åæ°ï¼
è¿åç±»åç¸å|**UnaryOperator**
`apply()`|**`UnaryOperator`
IntUnaryOperator
LongUnaryOperator
DoubleUnaryOperator**|
|2 åæ°ç±»åç¸åï¼
è¿åç±»åç¸å|**BinaryOperator**
`apply()`|**`BinaryOperator`
IntBinaryOperator
LongBinaryOperator
DoubleBinaryOperator**|
|2 åæ°ç±»åç¸å;
è¿åæ´å|Comparator
(java.util)
`compare()`|**`Comparator`**|
|2 åæ°ï¼
è¿åå¸å°å|**Predicate**
`test()`|**`Predicate`
`BiPredicate`
IntPredicate
LongPredicate
DoublePredicate**|
|åæ°åºæ¬ç±»åï¼
è¿ååºæ¬ç±»å|**ç±»åToç±»åFunction**
`applyAsç±»å()`|**IntToLongFunction
IntToDoubleFunction
LongToIntFunction
LongToDoubleFunction
DoubleToIntFunction
DoubleToLongFunction**|
|2 åæ°ç±»åä¸å|**Biæä½**
(ä¸åæ¹æ³å)|**`BiFunction`
`BiConsumer`
`BiPredicate`
`ToIntBiFunction`
`ToLongBiFunction`
`ToDoubleBiFunction`**|
æ¤è¡¨ä»
æä¾äºå¸¸è§æ¹æ¡ãéè¿ä¸è¡¨ï¼ä½ åºè¯¥æå¤æå°è½èªè¡æ¨å¯¼åºæ´å¤è¡ç彿°å¼æ¥å£ã
å¯ä»¥çåºï¼å¨å建 `java.util.function` æ¶ï¼è®¾è®¡è
们ååºäºä¸äºéæ©ã
ä¾å¦ï¼ä¸ºä»ä¹æ²¡æ `IntComparator`ï¼`LongComparator` å `DoubleComparator` å¢ï¼æ `BooleanSupplier` å´æ²¡æå
¶ä»è¡¨ç¤º **Boolean** çæ¥å£ï¼æéç¨ç `BiConsumer` å´æ²¡æç¨äº **int**ï¼**long** å **double** ç `BiConsumers` åä½ï¼æå¯¹ä»ä»¬æ¾å¼çåå 表示åæ
ï¼ãè¿äºéæ©æ¯çå¿½è¿æ¯æäººè®¤ä¸ºå
¶ä»ç»åçä½¿ç¨æ
åµåºç°å¾å¾å°ï¼ä»ä»¬æ¯å¦ä½å¾åºè¿ä¸ªç»è®ºçï¼ï¼
ä½ è¿å¯ä»¥çå°åºæ¬ç±»åç» Java æ·»å äºå¤å°å¤ææ§ã为äºç¼åæçé®é¢ï¼è¯¥è¯è¨ç第ä¸çä¸å°±å
å«äºåºæ¬ç±»åãç°å¨ï¼å¨è¯è¨ççå½å¨æä¸ï¼æä»¬ä»ç¶åå°è¯è¨è®¾è®¡éæ©ä¸ä½³çå½±åã
ä¸é¢æä¸¾äºåºäº Lambda 表达å¼çææä¸å **Function** åä½ç示ä¾ï¼
```java
// functional/FunctionVariants.java
import java.util.function.*;
class Foo {}
class Bar {
Foo f;
Bar(Foo f) { this.f = f; }
}
class IBaz {
int i;
IBaz(int i) {
this.i = i;
}
}
class LBaz {
long l;
LBaz(long l) {
this.l = l;
}
}
class DBaz {
double d;
DBaz(double d) {
this.d = d;
}
}
public class FunctionVariants {
static Function f1 = f -> new Bar(f);
static IntFunction f2 = i -> new IBaz(i);
static LongFunction f3 = l -> new LBaz(l);
static DoubleFunction f4 = d -> new DBaz(d);
static ToIntFunction f5 = ib -> ib.i;
static ToLongFunction f6 = lb -> lb.l;
static ToDoubleFunction f7 = db -> db.d;
static IntToLongFunction f8 = i -> i;
static IntToDoubleFunction f9 = i -> i;
static LongToIntFunction f10 = l -> (int)l;
static LongToDoubleFunction f11 = l -> l;
static DoubleToIntFunction f12 = d -> (int)d;
static DoubleToLongFunction f13 = d -> (long)d;
public static void main(String[] args) {
Bar b = f1.apply(new Foo());
IBaz ib = f2.apply(11);
LBaz lb = f3.apply(11);
DBaz db = f4.apply(11);
int i = f5.applyAsInt(ib);
long l = f6.applyAsLong(lb);
double d = f7.applyAsDouble(db);
l = f8.applyAsLong(12);
d = f9.applyAsDouble(12);
i = f10.applyAsInt(12);
d = f11.applyAsDouble(12);
i = f12.applyAsInt(13.0);
l = f13.applyAsLong(13.0);
}
}
```
è¿äº Lambda 表达å¼å°è¯çæéå彿°ç¾åçæç®ä»£ç ã å¨æäºæ
åµä¸ï¼æå¿
è¦è¿è¡å¼ºå¶ç±»å转æ¢ï¼å¦åç¼è¯å¨ä¼æ¥æªæé误ã
ä¸»æ¹æ³ä¸çæ¯ä¸ªæµè¯é½æ¾ç¤ºäº `Function` æ¥å£ä¸ä¸åç±»åç `apply()` æ¹æ³ã æ¯ä¸ªé½äº§çä¸ä¸ªä¸å
¶å
³èç Lambda 表达å¼çè°ç¨ã
æ¹æ³å¼ç¨æèªå·±çå°éæ³ï¼
```java
/ functional/MethodConversion.java
import java.util.function.*;
class In1 {}
class In2 {}
public class MethodConversion {
static void accept(In1 i1, In2 i2) {
System.out.println("accept()");
}
static void someOtherName(In1 i1, In2 i2) {
System.out.println("someOtherName()");
}
public static void main(String[] args) {
BiConsumer bic;
bic = MethodConversion::accept;
bic.accept(new In1(), new In2());
bic = MethodConversion::someOtherName;
// bic.someOtherName(new In1(), new In2()); // Nope
bic.accept(new In1(), new In2());
}
}
```
è¾åºç»æï¼
```
accept()
someOtherName()
```
æ¥ç `BiConsumer` çææ¡£ï¼ä½ ä¼çå° `accept()` æ¹æ³ã å®é
ä¸ï¼å¦ææä»¬å°æ¹æ³å½å为 `accept()`ï¼å®å°±å¯ä»¥ä½ä¸ºæ¹æ³å¼ç¨ã 使¯æä»¬ä¹å¯ç¨ä¸åçåç§°ï¼æ¯å¦ `someOtherName()`ãåªè¦åæ°ç±»åãè¿åç±»åä¸ `BiConsumer` ç `accept()` ç¸åå³å¯ã
å æ¤ï¼å¨ä½¿ç¨å½æ°æ¥å£æ¶ï¼åç§°æ å
³ç´§è¦ââåªè¦åæ°ç±»ååè¿åç±»åç¸åã Java ä¼å°ä½ çæ¹æ³æ å°å°æ¥å£æ¹æ³ã è¦è°ç¨æ¹æ³ï¼å¯ä»¥è°ç¨æ¥å£ç彿°å¼æ¹æ³åï¼å¨æ¬ä¾ä¸ä¸º `accept()`ï¼ï¼è䏿¯ä½ çæ¹æ³åã
ç°å¨æä»¬æ¥ççææåºäºç±»ç彿°å¼ï¼åºç¨äºæ¹æ³å¼ç¨ï¼å³é£äºä¸æ¶ååºæ¬ç±»åç彿°ï¼ãä¸ä¾æä»¬å建äºä¸ä¸ªæç®åç彿°å¼ç¾åã代ç 示ä¾ï¼
```java
// functional/ClassFunctionals.java
import java.util.*;
import java.util.function.*;
class AA {}
class BB {}
class CC {}
public class ClassFunctionals {
static AA f1() { return new AA(); }
static int f2(AA aa1, AA aa2) { return 1; }
static void f3(AA aa) {}
static void f4(AA aa, BB bb) {}
static CC f5(AA aa) { return new CC(); }
static CC f6(AA aa, BB bb) { return new CC(); }
static boolean f7(AA aa) { return true; }
static boolean f8(AA aa, BB bb) { return true; }
static AA f9(AA aa) { return new AA(); }
static AA f10(AA aa1, AA aa2) { return new AA(); }
public static void main(String[] args) {
Supplier s = ClassFunctionals::f1;
s.get();
Comparator c = ClassFunctionals::f2;
c.compare(new AA(), new AA());
Consumer cons = ClassFunctionals::f3;
cons.accept(new AA());
BiConsumer bicons = ClassFunctionals::f4;
bicons.accept(new AA(), new BB());
Function f = ClassFunctionals::f5;
CC cc = f.apply(new AA());
BiFunction bif = ClassFunctionals::f6;
cc = bif.apply(new AA(), new BB());
Predicate p = ClassFunctionals::f7;
boolean result = p.test(new AA());
BiPredicate bip = ClassFunctionals::f8;
result = bip.test(new AA(), new BB());
UnaryOperator uo = ClassFunctionals::f9;
AA aa = uo.apply(new AA());
BinaryOperator bo = ClassFunctionals::f10;
aa = bo.apply(new AA(), new AA());
}
}
```
请**注æ**ï¼æ¯ä¸ªæ¹æ³åç§°é½æ¯éæçï¼å¦ `f1()`ï¼`f2()`çï¼ãæ£å¦ä½ åæçå°çï¼ä¸æ¦å°æ¹æ³å¼ç¨èµå¼ç»å½æ°æ¥å£ï¼æä»¬å°±å¯ä»¥è°ç¨ä¸è¯¥æ¥å£å
³èç彿°æ¹æ³ã 卿¤ç¤ºä¾ä¸ä¸º `get()`ã`compare()`ã`accept()`ã`apply()` å `test()`ã
### å¤åæ°å½æ°å¼æ¥å£
`java.util.functional` ä¸çæ¥å£æ¯æéçãæ¯å¦æäº `BiFunction`ï¼ä½å®ä¸è½ååã 妿éè¦ä¸åæ°å½æ°çæ¥å£æä¹åï¼ å
¶å®è¿äºæ¥å£é常ç®åï¼å¾å®¹ææ¥ç Java åºæºä»£ç å¹¶èªè¡å建ã代ç 示ä¾ï¼
```java
// functional/TriFunction.java
@FunctionalInterface
public interface TriFunction {
R apply(T t, U u, V v);
}
```
ç®åæµè¯ï¼éªè¯å®æ¯å¦ææï¼
```java
// functional/TriFunctionTest.java
public class TriFunctionTest {
static int f(int i, long l, double d) { return 99; }
public static void main(String[] args) {
TriFunction tf =
TriFunctionTest::f;
tf = (i, l, d) -> 12;
}
}
```
è¿éæä»¬æµè¯äºæ¹æ³å¼ç¨å Lambda 表达å¼ã
### 缺å°åºæ¬ç±»åç彿°
让æä»¬é温ä¸ä¸ `BiConsumer`ï¼ççæä»¬å¦ä½åå»ºç¼ºå° **int**ï¼**long** å **double** çåç§æåï¼
```java
// functional/BiConsumerPermutations.java
import java.util.function.*;
public class BiConsumerPermutations {
static BiConsumer bicid = (i, d) ->
System.out.format("%d, %f%n", i, d);
static BiConsumer bicdi = (d, i) ->
System.out.format("%d, %f%n", i, d);
static BiConsumer bicil = (i, l) ->
System.out.format("%d, %d%n", i, l);
public static void main(String[] args) {
bicid.accept(47, 11.34);
bicdi.accept(22.45, 92);
bicil.accept(1, 11L);
}
}
```
è¾åºç»æï¼
```
47, 11.340000
92, 22.450000
1, 11
```
è¿éä½¿ç¨ `System.out.format()` æ¥æ¾ç¤ºãå®ç±»ä¼¼äº `System.out.println()` 使ä¾äºæ´å¤çæ¾ç¤ºé项ã è¿éï¼`%f` 表示æå° `n` ä½ä¸ºæµ®ç¹å¼ç»åºï¼`%d` 表示 `n` æ¯ä¸ä¸ªæ´æ°å¼ã è¿å
¶ä¸å¯ä»¥å
å«ç©ºæ ¼ï¼è¾å
¥ `%n` 伿¢è¡ â å½ç¶ä½¿ç¨ä¼ ç»ç `\n` ä¹è½æ¢è¡ï¼ä½ `%n` æ¯èªå¨è·¨å¹³å°çï¼è¿æ¯ä½¿ç¨ `format()` çå¦ä¸ä¸ªåå ã
ä¸ä¾ç®å使ç¨äºå
è£
ç±»åï¼è£
ç®±åæç®±ç¨äºå¨åºæ¬ç±»åä¹é´æ¥å转æ¢ã æä»¬ä¹å¯ä»¥ä½¿ç¨å
è£
ç±»åï¼å¦ `Function`ï¼è䏿¯é¢å®ä¹çåºæ¬ç±»åã代ç 示ä¾ï¼
```java
// functional/FunctionWithWrapped.java
import java.util.function.*;
public class FunctionWithWrapped {
public static void main(String[] args) {
Function fid = i -> (double)i;
IntToDoubleFunction fid2 = i -> i;
}
}
```
å¦ææ²¡æå¼ºå¶è½¬æ¢ï¼å伿¶å°éè¯¯æ¶æ¯ï¼âInteger cannot be converted to Doubleâï¼**Integer** æ æ³è½¬æ¢ä¸º **Double**ï¼ï¼èä½¿ç¨ **IntToDoubleFunction** å°±æ²¡ææ¤ç±»é®é¢ã **IntToDoubleFunction** æ¥å£çæºä»£ç æ¯è¿æ ·çï¼
```java
@FunctionalInterface
public interface IntToDoubleFunction {
double applyAsDouble(int value);
}
```
乿以æä»¬å¯ä»¥ç®åå°ç¼å `Function ` å¹¶è¿ååéçç»æï¼å¾ææ¾æ¯ä¸ºäºæ§è½ã使ç¨åºæ¬ç±»åå¯ä»¥é²æ¢ä¼ éåæ°åè¿åç»æè¿ç¨ä¸çèªå¨è£
ç®±åèªå¨æç®±ã
似乿¯èèå°ä½¿ç¨é¢çï¼æäºå½æ°ç±»å并没æé¢å®ä¹ã
å½ç¶ï¼å¦æå 缺å°åºæ¬ç±»åèé æçæ§è½é®é¢ï¼ä½ ä¹å¯ä»¥è½»æ¾ç¼åèªå·±çæ¥å£ï¼ åè Java æºä»£ç ï¼ââ尽管è¿éåºç°æ§è½ç¶é¢çå¯è½æ§ä¸å¤§ã
## é«é¶å½æ°
è¿ä¸ªååå¯è½å¬èµ·æ¥ä»¤äººççï¼ä½æ¯ï¼[é«é¶å½æ°](https://en.wikipedia.org/wiki/Higher-order_function)ï¼Higher-order Functionï¼åªæ¯ä¸ä¸ªæ¶è´¹æäº§ç彿°ç彿°ã
æä»¬å
æ¥ççå¦ä½äº§çä¸ä¸ªå½æ°ï¼
```java
// functional/ProduceFunction.java
import java.util.function.*;
interface
FuncSS extends Function {} // [1]
public class ProduceFunction {
static FuncSS produce() {
return s -> s.toLowerCase(); // [2]
}
public static void main(String[] args) {
FuncSS f = produce();
System.out.println(f.apply("YELLING"));
}
}
```
è¾åºç»æï¼
```
yelling
```
è¿éï¼`produce()` æ¯é«é¶å½æ°ã
**[1]** 使ç¨ç»§æ¿ï¼å¯ä»¥è½»æ¾å°ä¸ºä¸ç¨æ¥å£å建å«åã
**[2]** ä½¿ç¨ Lambda 表达å¼ï¼å¯ä»¥è½»æ¾å°å¨æ¹æ³ä¸å建åè¿åä¸ä¸ªå½æ°ã
è¦æ¶è´¹ä¸ä¸ªå½æ°ï¼æ¶è´¹å½æ°éè¦å¨åæ°å表æ£ç¡®å°æè¿°å½æ°ç±»åã代ç 示ä¾ï¼
```java
// functional/ConsumeFunction.java
import java.util.function.*;
class One {}
class Two {}
public class ConsumeFunction {
static Two consume(Function onetwo) {
return onetwo.apply(new One());
}
public static void main(String[] args) {
Two two = consume(one -> new Two());
}
}
```
å½åºäºæ¶è´¹å½æ°çææ°å½æ°æ¶ï¼äºæ
å°±åå¾ç¸å½æè¶£äºã代ç 示ä¾å¦ä¸ï¼
```java
// functional/TransformFunction.java
import java.util.function.*;
class I {
@Override
public String toString() { return "I"; }
}
class O {
@Override
public String toString() { return "O"; }
}
public class TransformFunction {
static Function transform(Function in) {
return in.andThen(o -> {
System.out.println(o);
return o;
});
}
public static void main(String[] args) {
Function f2 = transform(i -> {
System.out.println(i);
return new O();
});
O o = f2.apply(new I());
}
}
```
è¾åºç»æï¼
```
I
O
```
å¨è¿éï¼`transform()` çæä¸ä¸ªä¸ä¼ å
¥ç彿°å
·æç¸åç¾åç彿°ï¼ä½æ¯ä½ å¯ä»¥çæä»»ä½ä½ æ³è¦çç±»åã
è¿é使ç¨å°äº `Function` æ¥å£ä¸å为 `andThen()` çé»è®¤æ¹æ³ï¼è¯¥æ¹æ³ä¸é¨ç¨äºæä½å½æ°ã 顾åæä¹ï¼å¨è°ç¨ `in` 彿°ä¹åè°ç¨ `toThen()`ï¼è¿æä¸ª `compose()` æ¹æ³ï¼å®å¨ `in` 彿°ä¹ååºç¨æ°å½æ°ï¼ã è¦éå ä¸ä¸ª `andThen()` 彿°ï¼æä»¬åªéå°è¯¥å½æ°ä½ä¸ºåæ°ä¼ éã `transform()` 产ççæ¯ä¸ä¸ªæ°å½æ°ï¼å®å° `in` çå¨ä½ä¸ `andThen()` åæ°çå¨ä½ç»åèµ·æ¥ã
## éå
å¨ä¸ä¸èç `ProduceFunction.java` ä¸ï¼æä»¬ä»æ¹æ³ä¸è¿å Lambda 彿°ã è½ç¶è¿ç¨ç®åï¼ä½æ¯æäºé®é¢å¿
é¡»ååè¿å¤´æ¥æ¢è®¨ä¸ä¸ã
**éå
**ï¼Closureï¼ä¸è¯æ»ç»äºè¿äºé®é¢ã å®é常éè¦ï¼å©ç¨éå
å¯ä»¥è½»æ¾çæå½æ°ã
èèä¸ä¸ªæ´å¤æç Lambdaï¼å®ä½¿ç¨å½æ°ä½ç¨åä¹å¤çåéã è¿åè¯¥å½æ°ä¼åçä»ä¹ï¼ ä¹å°±æ¯è¯´ï¼å½ä½ è°ç¨å½æ°æ¶ï¼å®å¯¹é£äº âå¤é¨ âåéå¼ç¨äºä»ä¹? 妿è¯è¨ä¸è½èªå¨è§£å³è¿ä¸ªé®é¢ï¼é£å°åå¾é常å
·ææææ§ã è½å¤è§£å³è¿ä¸ªé®é¢çè¯è¨è¢«ç§°ä¸º**æ¯æéå
**ï¼æè
å«ä½å¨è¯æ³ä¸éå®èå´( ä¹ä½¿ç¨æ¯è¯*åéæè·* )ãJava 8 æä¾äºæéä½åççéå
æ¯æï¼æä»¬å°ç¨ä¸äºç®åçä¾åæ¥ç ç©¶å®ã
é¦å
ï¼ä¸ä¾å½æ°ä¸ï¼æ¹æ³è¿å访é®å¯¹è±¡åæ®µåæ¹æ³åæ°ã代ç 示ä¾ï¼
```java
// functional/Closure1.java
import java.util.function.*;
public class Closure1 {
int i;
IntSupplier makeFun(int x) {
return () -> x + i++;
}
}
```
使¯ï¼ä»ç»èèä¸ä¸ï¼`i` çè¿ç§ç¨æ³å¹¶éæ¯ä¸ªå¤§é¾é¢ï¼å 为对象å¾å¯è½å¨ä½ è°ç¨ `makeFun()` ä¹åå°±åå¨äºââå®é
ä¸ï¼å徿¶éå¨å ä¹è¯å®ä¼ä¿çä¸ä¸ªå¯¹è±¡ï¼å¹¶å°ç°æç彿°ä»¥è¿ç§æ¹å¼ç»å®å°è¯¥å¯¹è±¡ä¸[^5]ãå½ç¶ï¼å¦æä½ 对åä¸ä¸ªå¯¹è±¡å¤æ¬¡è°ç¨ `makeFun()` ï¼ä½ æç»ä¼å¾å°å¤ä¸ªå½æ°ï¼å®ä»¬å
±äº« `i` çåå¨ç©ºé´ï¼
```java
// functional/SharedStorage.java
import java.util.function.*;
public class SharedStorage {
public static void main(String[] args) {
Closure1 c1 = new Closure1();
IntSupplier f1 = c1.makeFun(0);
IntSupplier f2 = c1.makeFun(0);
IntSupplier f3 = c1.makeFun(0);
System.out.println(f1.getAsInt());
System.out.println(f2.getAsInt());
System.out.println(f3.getAsInt());
}
}
```
è¾åºç»æï¼
```
0
1
2
```
æ¯æ¬¡è°ç¨ `getAsInt()` é½ä¼å¢å `i`ï¼è¡¨æå卿¯å
±äº«çã
妿 `i` æ¯ `makeFun()` çå±é¨åéæä¹åï¼ å¨æ£å¸¸æ
åµä¸ï¼å½ `makeFun()` å®ææ¶ `i` å°±æ¶å¤±ã ä½å®ä»å¯ä»¥ç¼è¯ï¼
```java
// functional/Closure2.java
import java.util.function.*;
public class Closure2 {
IntSupplier makeFun(int x) {
int i = 0;
return () -> x + i;
}
}
```
ç± `makeFun()` è¿åç `IntSupplier` âå
³éâ `i` å `x`ï¼å æ¤å½ä½ è°ç¨è¿åç彿°æ¶ä¸¤è
ä»ç¶ææã ä½è¯·**注æ**ï¼ææ²¡æå `Closure1.java` 飿 ·éå¢ `i`ï¼å 为ä¼äº§çç¼è¯æ¶é误ã代ç 示ä¾ï¼
```java
// functional/Closure3.java
// {WillNotCompile}
import java.util.function.*;
public class Closure3 {
IntSupplier makeFun(int x) {
int i = 0;
// x++ å i++ é½ä¼æ¥éï¼
return () -> x++ + i++;
}
}
```
`x` å `i` çæä½é½ç¯äºåæ ·çé误ï¼ä» Lambda 表达å¼å¼ç¨çå±é¨åéå¿
é¡»æ¯ `final` æè
æ¯çå `final` ææçã
å¦æä½¿ç¨ `final` 修饰 `x`å `i`ï¼å°±ä¸è½åéå¢å®ä»¬çå¼äºã代ç 示ä¾ï¼
```java
// functional/Closure4.java
import java.util.function.*;
public class Closure4 {
IntSupplier makeFun(final int x) {
final int i = 0;
return () -> x + i;
}
}
```
é£ä¹ä¸ºä»ä¹å¨ `Closure2.java` ä¸ï¼ `x` å `i` é `final` å´å¯ä»¥è¿è¡å¢ï¼
è¿å°±å«å**çå final ææ**ï¼Effectively Finalï¼ãè¿ä¸ªæ¯è¯æ¯å¨ Java 8 æå¼å§åºç°çï¼è¡¨ç¤ºè½ç¶æ²¡ææç¡®å°å£°æå鿝 `final` çï¼ä½æ¯å åé弿²¡è¢«æ¹åè¿èå®é
æäº `final` åççææã 妿å±é¨åéçåå§å¼æ°¸è¿ä¸ä¼æ¹åï¼é£ä¹å®å®é
ä¸å°±æ¯ `final` çã
妿 `x` å `i` çå¼å¨æ¹æ³ä¸çå
¶ä»ä½ç½®åçæ¹åï¼ä½ä¸å¨è¿åç彿°å
é¨ï¼ï¼åç¼è¯å¨ä»å°è§å
¶ä¸ºéè¯¯ãæ¯ä¸ªé墿ä½åä¼åå«äº§çéè¯¯æ¶æ¯ã代ç 示ä¾ï¼
```java
/ functional/Closure5.java
// {æ æ³ç¼è¯æå}
import java.util.function.*;
public class Closure5 {
IntSupplier makeFun(int x) {
int i = 0;
i++;
x++;
return () -> x + i;
}
}
```
**çå final ææ**æå³çå¯ä»¥å¨åé声æåå ä¸ **final** å
³é®åèä¸ç¨æ´æ¹ä»»ä½å
¶ä½ä»£ç ã å®é
ä¸å®å°±æ¯å
·å¤ `final` ææçï¼åªæ¯æ²¡ææç¡®è¯´æã
éè¿å¨éå
ä¸ä½¿ç¨ `final` å
³é®åæå修饰åé `x` å `i` ï¼ æä»¬è§£å³äº `Closure5.java` ä¸çé®é¢ã代ç 示ä¾ï¼
```java
// functional/Closure6.java
import java.util.function.*;
public class Closure6 {
IntSupplier makeFun(int x) {
int i = 0;
i++;
x++;
final int iFinal = i;
final int xFinal = x;
return () -> xFinal + iFinal;
}
}
```
ä¸ä¾ä¸ `iFinal` å `xFinal` çå¼å¨èµå¼åå¹¶æ²¡ææ¹åè¿ï¼å æ¤å¨è¿éä½¿ç¨ `final` æ¯å¤ä½çã
妿è¿éæ¯å¼ç¨çè¯ï¼éè¦æ **int** åæ´æ¹ä¸º **Integer** åã代ç 示ä¾ï¼
```java
// functional/Closure7.java
// {æ æ³ç¼è¯æå}
import java.util.function.*;
public class Closure7 {
IntSupplier makeFun(int x) {
Integer i = 0;
i = i + 1;
return () -> x + i;
}
}
```
ç¼è¯å¨é常æºè½ï¼å®è½è¯å«åé `i` çå¼è¢«æ´æ¹è¿äºã 对äºå
è£
ç±»åçå¤çå¯è½æ¯è¾ç¹æ®ï¼å æ¤æä»¬å°è¯ä¸ **List**ï¼
```java
// functional/Closure8.java
import java.util.*;
import java.util.function.*;
public class Closure8 {
Supplier> makeFun() {
final List ai = new ArrayList<>();
ai.add(1);
return () -> ai;
}
public static void main(String[] args) {
Closure8 c7 = new Closure8();
List
l1 = c7.makeFun().get(),
l2 = c7.makeFun().get();
System.out.println(l1);
System.out.println(l2);
l1.add(42);
l2.add(96);
System.out.println(l1);
System.out.println(l2);
}
}
```
è¾åºç»æï¼
```
[1]
[1]
[1, 42]
[1, 96]
```
å¯ä»¥çå°ï¼è¿æ¬¡ä¸åæ£å¸¸ãæä»¬æ¹åäº **List** çå¼å´æ²¡äº§çç¼è¯æ¶é误ãéè¿è§å¯æ¬ä¾çè¾åºç»æï¼æä»¬åç°è¿çèµ·æ¥é常å®å
¨ãè¿æ¯å ä¸ºæ¯æ¬¡è°ç¨ `makeFun()` æ¶ï¼å
¶å®é½ä¼å建并è¿åä¸ä¸ªå
¨æ°ç `ArrayList`ã ä¹å°±æ¯è¯´ï¼æ¯ä¸ªéå
齿èªå·±ç¬ç«ç `ArrayList`ï¼ å®ä»¬ä¹é´äºä¸å¹²æ°ã
请**注æ**æå·²ç»å£°æ `ai` æ¯ `final` çäºã尽管å¨è¿ä¸ªä¾åä¸ä½ å¯ä»¥å»æ `final` å¹¶å¾å°ç¸åçç»æï¼è¯è¯å§ï¼ï¼ã åºç¨äºå¯¹è±¡å¼ç¨ç `final` å
³é®åä»
表示ä¸ä¼éæ°èµå¼å¼ç¨ã å®å¹¶ä¸ä»£è¡¨ä½ ä¸è½ä¿®æ¹å¯¹è±¡æ¬èº«ã
ä¸é¢æä»¬æ¥çç `Closure7.java` å `Closure8.java` ä¹é´çåºå«ãæä»¬çå°ï¼å¨ `Closure7.java` ä¸åé `i` æè¿éæ°èµå¼ã ä¹è®¸è¿å°±æ¯**çå final ææ**éè¯¯æ¶æ¯ç触åç¹ã
```java
// functional/Closure9.java
// {æ æ³ç¼è¯æå}
import java.util.*;
import java.util.function.*;
public class Closure9 {
Supplier> makeFun() {
List ai = new ArrayList<>();
ai = new ArrayList<>(); // Reassignment
return () -> ai;
}
}
```
ä¸ä¾ï¼éæ°èµå¼å¼ç¨ä¼è§¦åéè¯¯æ¶æ¯ã妿åªä¿®æ¹æåçå¯¹è±¡åæ²¡é®é¢ï¼åªè¦æ²¡æå
¶ä»äººè·å¾å¯¹è¯¥å¯¹è±¡çå¼ç¨ï¼è¿æå³çä½ æå¤ä¸ªå®ä½å¯ä»¥ä¿®æ¹å¯¹è±¡ï¼æ¤æ¶äºæ
ä¼åå¾é常混乱ï¼ï¼åºæ¬ä¸å°±æ¯å®å
¨ç[^6]ã
让æä»¬å顾ä¸ä¸ `Closure1.java`ãé£ä¹ç°å¨é®é¢æ¥äºï¼ä¸ºä»ä¹åé `i` 被修æ¹ç¼è¯å¨å´æ²¡ææ¥éå¢ã 宿¢ä¸æ¯ `final` çï¼ä¹ä¸æ¯**çå final ææ**çãå 为 `i` æ¯å¤å´ç±»çæåï¼æä»¥è¿æ ·åè¯å®æ¯å®å
¨çï¼é¤éä½ æ£å¨å建å
±äº«å¯åå
åçå¤ä¸ªå½æ°ï¼ãæ¯çï¼ä½ å¯ä»¥è¾©ç§°å¨è¿ç§æ
åµä¸ä¸ä¼åçåéæè·ï¼Variable Captureï¼ãä½å¯ä»¥è¯å®çæ¯ï¼`Closure3.java` çéè¯¯æ¶æ¯æ¯ä¸é¨é对å±é¨åéçãå æ¤ï¼è§åå¹¶éåªæ¯âå¨ Lambda ä¹å¤å®ä¹çä»»ä½åéå¿
é¡»æ¯ `final` çæ**çå final ææ**é£ä¹ç®åãç¸åï¼ä½ å¿
é¡»èèæè·çå鿝妿¯**çå final ææ**çã 妿宿¯å¯¹è±¡ä¸çåæ®µï¼é£ä¹å®æ¥æç¬ç«ççå卿ï¼å¹¶ä¸ä¸éè¦ä»»ä½ç¹æ®çæè·ï¼ä»¥ä¾¿ç¨åå¨è°ç¨ Lambda æ¶åå¨ã
### ä½ä¸ºéå
çå
é¨ç±»
æä»¬å¯ä»¥ä½¿ç¨å¿åå
é¨ç±»éåä¹åçä¾å:
```java
// functional/AnonymousClosure.java
import java.util.function.*;
public class AnonymousClosure {
IntSupplier makeFun(int x) {
int i = 0;
// åæ ·è§åçåºç¨:
// i++; // éçå final ææ
// x++; // åä¸
return new IntSupplier() {
public int getAsInt() { return x + i; }
};
}
}
```
å®é
ä¸åªè¦æå
é¨ç±»ï¼å°±ä¼æéå
ï¼Java 8 åªæ¯ç®åäºéå
æä½ï¼ãå¨ Java 8 ä¹åï¼åé `x` å `i` å¿
须被æç¡®å£°æä¸º `final`ãå¨ Java 8 ä¸ï¼å
é¨ç±»çè§åæ¾å®½ï¼å
æ¬**çå final ææ**ã
## 彿°ç»å
彿°ç»åï¼Function Compositionï¼æä¸ºâå¤ä¸ªå½æ°ç»åææ°å½æ°âãå®é常æ¯å½æ°å¼ç¼ç¨çåºæ¬ç»æé¨åãå¨åé¢ç `TransformFunction.java` ç±»ä¸ï¼æä¸ä¸ªä½¿ç¨ `andThen()` ç彿°ç»å示ä¾ãä¸äº `java.util.function` æ¥å£ä¸å
嫿¯æå½æ°ç»åçæ¹æ³ [^7]ã
| ç»åæ¹æ³ | æ¯ææ¥å£ |
| :----- | :----- |
| `andThen(argument)`
æ ¹æ®åæ°æ§è¡åå§æä½ | **Function
BiFunction
Consumer
BiConsumer
IntConsumer
LongConsumer
DoubleConsumer
UnaryOperator
IntUnaryOperator
LongUnaryOperator
DoubleUnaryOperator
BinaryOperator** |
| `compose(argument)`
æ ¹æ®åæ°æ§è¡åå§æä½ | **Function
UnaryOperator
IntUnaryOperator
LongUnaryOperator
DoubleUnaryOperator** |
| `and(argument)`
çè·¯**é»è¾ä¸**åå§è°è¯ååæ°è°è¯ | **Predicate
BiPredicate
IntPredicate
LongPredicate
DoublePredicate** |
| `or(argument)`
çè·¯**é»è¾æ**åå§è°è¯ååæ°è°è¯ | **Predicate
BiPredicate
IntPredicate
LongPredicate
DoublePredicate** |
| `negate()`
该è°è¯ç**é»è¾å¦**è°è¯| **Predicate
BiPredicate
IntPredicate
LongPredicate
DoublePredicate** |
ä¸ä¾ä½¿ç¨äº `Function` éç `compose()`å `andThen()`ã代ç 示ä¾ï¼
```java
// functional/FunctionComposition.java
import java.util.function.*;
public class FunctionComposition {
static Function
f1 = s -> {
System.out.println(s);
return s.replace('A', '_');
},
f2 = s -> s.substring(3),
f3 = s -> s.toLowerCase(),
f4 = f1.compose(f2).andThen(f3);
public static void main(String[] args) {
System.out.println(
f4.apply("GO AFTER ALL AMBULANCES"));
}
}
```
è¾åºç»æï¼
```
AFTER ALL AMBULANCES
_fter _ll _mbul_nces
```
è¿éæä»¬éç¹çæ£å¨åå»ºçæ°å½æ° `f4`ãå®è°ç¨ `apply()` çæ¹å¼ä¸å¸¸è§å 乿 å¼[^8]ã
å½ `f1` è·å¾å符串æ¶ï¼å®å·²ç»è¢«`f2` å¥ç¦»äºåä¸ä¸ªå符ãè¿æ¯å 为 `composeï¼f2ï¼` 表示 `f2` çè°ç¨åçå¨ `f1` ä¹åã
ä¸ä¾æ¯ `Predicate` çé»è¾è¿ç®æ¼ç¤º.代ç 示ä¾ï¼
```java
// functional/PredicateComposition.java
import java.util.function.*;
import java.util.stream.*;
public class PredicateComposition {
static Predicate
p1 = s -> s.contains("bar"),
p2 = s -> s.length() < 5,
p3 = s -> s.contains("foo"),
p4 = p1.negate().and(p2).or(p3);
public static void main(String[] args) {
Stream.of("bar", "foobar", "foobaz", "fongopuckey")
.filter(p4)
.forEach(System.out::println);
}
}
```
è¾åºç»æï¼
```
foobar
foobaz
```
`p4` è·åå°äºææè°è¯å¹¶ç»åæä¸ä¸ªæ´å¤æçè°è¯ã解读ï¼å¦æå符串ä¸ä¸å
å« `bar` ä¸é¿åº¦å°äº 5ï¼æè
å®å
å« `foo` ï¼åç»æä¸º `true`ã
æ£å å®äº§ç妿¤æ¸
æ°çè¯æ³ï¼æå¨ä¸»æ¹æ³ä¸éç¨äºä¸äºå°æå·§ï¼å¹¶åç¨äºä¸ä¸ç« çå
容ãé¦å
ï¼æå建äºä¸ä¸ªåç¬¦ä¸²å¯¹è±¡çæµï¼ç¶åå°æ¯ä¸ªå¯¹è±¡ä¼ éç» `filter()` æä½ã `filter()` ä½¿ç¨ `p4` çè°è¯æ¥ç¡®å®å¯¹è±¡çå»çãæåæä»¬ä½¿ç¨ `forEach()` å° `println` æ¹æ³å¼ç¨åºç¨å¨æ¯ä¸ªçåç对象ä¸ã
ä»è¾åºç»ææä»¬å¯ä»¥çå° `p4` ç工使µç¨ï¼ä»»ä½å¸¦æ `foo` çä¸è¥¿é½ä¼çä¸ï¼å³ä½¿å®çé¿åº¦å¤§äº 5ã `fongopuckey` å é¿åº¦è¶
åºåä¸å
å« `bar` è被丢å¼ã
## æ¯éååé¨åæ±å¼
[æ¯éå](https://en.wikipedia.org/wiki/Currying)ï¼Curryingï¼çåç§°æ¥èªäºå
¶åæè
ä¹ä¸ *Haskell Curry*ãä»å¯è½æ¯è®¡ç®æºé¢åå¯ä¸åå被å½åéè¦æ¦å¿µç人ï¼å¦å¤å°±æ¯ Haskell ç¼ç¨è¯è¨ï¼ã æ¯éåæä¸ºï¼å°ä¸ä¸ªå¤åæ°ç彿°ï¼è½¬æ¢ä¸ºä¸ç³»åå忰彿°ã
```java
// functional/CurryingAndPartials.java
import java.util.function.*;
public class CurryingAndPartials {
// æªæ¯éå:
static String uncurried(String a, String b) {
return a + b;
}
public static void main(String[] args) {
// æ¯éåç彿°:
Function> sum =
a -> b -> a + b; // [1]
System.out.println(uncurried("Hi ", "Ho"));
Function
hi = sum.apply("Hi "); // [2]
System.out.println(hi.apply("Ho"));
// é¨ååºç¨:
Function sumHi =
sum.apply("Hup ");
System.out.println(sumHi.apply("Ho"));
System.out.println(sumHi.apply("Hey"));
}
}
```
è¾åºç»æï¼
```
Hi Ho
Hi Ho
Hup Ho
Hup Hey
```
**[1]** è¿ä¸è¿ä¸²çç®å¤´å¾å·§å¦ã*注æ*ï¼å¨å½æ°æ¥å£å£°æä¸ï¼ç¬¬äºä¸ªåæ°æ¯å¦ä¸ä¸ªå½æ°ã
**[2]** æ¯éåçç®çæ¯è½å¤éè¿æä¾ä¸ä¸ªåæ°æ¥å建ä¸ä¸ªæ°å½æ°ï¼æä»¥ç°å¨æäºä¸ä¸ªâ带å彿°âåå©ä¸ç âæ å彿°â ãå®é
ä¸ï¼ä½ ä»ä¸ä¸ªå忰彿°å¼å§ï¼æåå¾å°ä¸ä¸ªå忰彿°ã
æä»¬å¯ä»¥éè¿æ·»å çº§å«æ¥æ¯éåä¸ä¸ªä¸åæ°å½æ°ï¼
```java
// functional/Curry3Args.java
import java.util.function.*;
public class Curry3Args {
public static void main(String[] args) {
Function>> sum =
a -> b -> c -> a + b + c;
Function> hi =
sum.apply("Hi ");
Function ho =
hi.apply("Ho ");
System.out.println(ho.apply("Hup"));
}
}
```
è¾åºç»æï¼
```
Hi Ho Hup
```
å¯¹äºæ¯ä¸ªçº§å«çç®å¤´çº§èï¼Arrow-cascadingï¼ï¼ä½ å¨ç±»å声æä¸å
裹äºå¦ä¸ä¸ª **Function**ã
å¤çåºæ¬ç±»ååè£
ç®±æ¶ï¼è¯·ä½¿ç¨éå½ç **Function** æ¥å£ï¼
```java
// functional/CurriedIntAdd.java
import java.util.function.*;
public class CurriedIntAdd {
public static void main(String[] args) {
IntFunction
curriedIntAdd = a -> b -> a + b;
IntUnaryOperator add4 = curriedIntAdd.apply(4);
System.out.println(add4.applyAsInt(5));
}
}
```
è¾åºç»æï¼
```
9
```
å¯ä»¥å¨äºèç½ä¸æ¾å°æ´å¤çæ¯éå示ä¾ãé常å®ä»¬æ¯ç¨ Java ä¹å¤çè¯è¨å®ç°çï¼ä½å¦æçè§£äºæ¯éåçåºæ¬æ¦å¿µï¼ä½ å¯ä»¥å¾è½»æ¾å°ç¨ Java å®ç°å®ä»¬ã
## çº¯å½æ°å¼ç¼ç¨
å³ä½¿æ²¡æå½æ°å¼æ¯æï¼å C è¿æ ·çåºç¡è¯è¨ï¼ä¹å¯ä»¥æç
§ä¸å®çååç¼åçº¯å½æ°å¼ç¨åºãJava 8 è®©å½æ°å¼ç¼ç¨æ´ç®åï¼ä¸è¿æä»¬è¦ç¡®ä¿ä¸åæ¯ `final` çï¼åæ¶ä½ çæææ¹æ³å彿°æ²¡æå¯ä½ç¨ãå 为 Java 卿¬è´¨ä¸å¹¶éæ¯ä¸å¯åè¯è¨ï¼æä»¬æ æ³éè¿ç¼è¯å¨æ¥éã
è¿ç§æ
åµä¸ï¼æä»¬å¯ä»¥åå©ç¬¬ä¸æ¹å·¥å
·[^9]ï¼ä½ä½¿ç¨ Scala æ Clojure è¿æ ·çè¯è¨å¯è½æ´ç®åãå 为å®ä»¬ä»ä¸å¼å§å°±æ¯ä¸ºä¿æä¸åæ§è设计çãä½ å¯ä»¥éç¨è¿äºè¯è¨æ¥ç¼åä½ ç Java 项ç®çä¸é¨åã妿å¿
é¡»è¦ç¨çº¯å½æ°å¼ç¼åï¼åå¯ä»¥ç¨ Scalaï¼éè¦ä¸äºè§åï¼ æ Clojure ï¼éè¦çè§åæ´å°ï¼ãè½ç¶ Java æ¯æ[å¹¶åç¼ç¨](./24-Concurrent-Programming.md)ï¼ä½å¦æè¿æ¯ä½ 项ç®çæ ¸å¿é¨åï¼ä½ åºè¯¥èèå¨é¡¹ç®é¨ååè½ä¸ä½¿ç¨ `Scala` æ `Clojure` ä¹ç±»çè¯è¨ã
## æ¬ç« å°ç»
Lambda 表达å¼åæ¹æ³å¼ç¨å¹¶æ²¡æå° Java è½¬æ¢æå½æ°å¼è¯è¨ï¼èæ¯æä¾äºå¯¹å½æ°å¼ç¼ç¨çæ¯æãè¿å¯¹ Java æ¥è¯´æ¯ä¸ä¸ªå·¨å¤§çæ¹è¿ãå 为è¿å
è®¸ä½ ç¼åæ´ç®æ´æäºï¼æäºçè§£ç代ç ãå¨ä¸ä¸ç« ä¸ï¼ä½ ä¼çå°å®ä»¬å¨æµå¼ç¼ç¨ä¸çåºç¨ãç¸ä¿¡ä½ ä¼åæä¸æ ·ï¼åæ¬¢ä¸æµå¼ç¼ç¨ã
è¿äºç¹æ§æ»¡è¶³å¤§é¨å Java ç¨åºåçéæ±ãä»ä»¬å¼å§ç¾¡æ
å«å¦ ClojureãScala è¿ç±»æ°è¯è¨çåè½ï¼å¹¶è¯å¾é»æ¢ Java ç¨åºåæµå¤±å°å
¶ä»éµè¥ ï¼å°±ç®ä¸è½é»æ¢ï¼èµ·ç æä¾äºæ´å¥½çéæ©ï¼ã
使¯ï¼Lambdas åæ¹æ³å¼ç¨è¿éå®ç¾ï¼æä»¬æ°¸è¿è¦ä¸º Java 设计è
æ©æçèçå³å®ä»åºä»£ä»·ãç¹å«æ¯æ²¡ææ³å Lambdaï¼æä»¥ Lambda å¨ Java ä¸å¹¶éä¸çå
¬æ°ãè½ç¶æä¸å¦è®¤ Java 8 ç巨大æ¹è¿ï¼ä½è¿æå³çåè®¸å¤ Java ç¹æ§ä¸æ ·ï¼å®ç使ç¨è¿æ¯ä¼è®©äººæè§æ²®ä¸§å鸡èã
å½ä½ éå°å¦ä¹ å°é¾æ¶ï¼è¯·è®°ä½éè¿ IDEï¼NetBeansãIntelliJ Idea å Eclipseï¼è·å¾å¸®å©ï¼å 为 IDE å¯ä»¥æºè½æç¤ºä½ 使¶ä½¿ç¨ Lambda è¡¨è¾¾å¼ææ¹æ³å¼ç¨ï¼çè³ææ¶è¿è½ä¸ºä½ ä¼å代ç ã
[^1]: åè½ç²è´´å¨ä¸èµ·çæ¹æ³çç¡®æç¹ä¸ä¼ä¸åï¼ä½å®ä»ä¸å¤±ä¸ºä¸ä¸ªåºã
[^2]: ä¾å¦,è¿ä¸ªçµå书æ¯å©ç¨ [Pandoc](http://pandoc.org/) å¶ä½åºæ¥çï¼å®æ¯ç¨çº¯å½æ°å¼è¯è¨ [Haskell](https://www.haskell.org/) ç¼åçä¸ä¸ªç¨åº ã
[^3]: ææ¶å½æ°å¼è¯è¨å°å
¶æè¿°ä¸ºâ代ç 峿°æ®âã
[^4]: è¿ä¸ªè¯æ³æ¥èª C++ã
[^5]: æè¿æ²¡æéªè¯è¿è¿ç§è¯´æ³ã
[^6]: å½ä½ çè§£äº[å¹¶åç¼ç¨](./24-Concurrent-Programming.md)ç« èçå
容ï¼ä½ å°±è½æç½ä¸ºä»ä¹æ´æ¹å
±äº«åé â䏿¯çº¿ç¨å®å
¨çâ çäºã
[^7]: æ¥å£è½å¤æ¯ææ¹æ³çåå æ¯å®ä»¬æ¯ Java 8 é»è®¤æ¹æ³ï¼ä½ å°å¨ä¸ä¸ç« ä¸äºè§£å°ã
[^8]: ä¸äºè¯è¨ï¼å¦ Pythonï¼å
许åè°ç¨å
¶ä»å½æ°ä¸æ ·è°ç¨ç»å彿°ãä½è¿æ¯ Javaï¼æä»¥æä»¬ååå¯ä¸ºä¹äºã
[^9]: ä¾å¦ï¼[Immutables](https://immutables.github.io/) å [Mutability Detector](https://mutabilitydetector.github.io/MutabilityDetector/)ã