变量不合法的表达式JAVA_Java8中lambda表达式的语法,别人都会的,你还不会吗?「一」...
函數(shù)式編程
函數(shù)式編程是一種編程方式,它將電腦運(yùn)算視為函數(shù)的計(jì)算。函數(shù)編程語(yǔ)言最重要的基礎(chǔ)是λ演算(lambda calculus),λ演算的函數(shù)可以接受函數(shù)當(dāng)作輸入(參數(shù))和輸出(返回值)。 函數(shù)式編程是"結(jié)構(gòu)化編程"的一種,主要思想是把運(yùn)算過(guò)程盡量寫成一系列嵌套的函數(shù)調(diào)用。
lambda表達(dá)式
JSR-335首次定義了在Java中使用lambda表達(dá)式的基本規(guī)范,當(dāng)前的實(shí)現(xiàn)就是針對(duì)JSR-335規(guī)范的。 lambda表達(dá)式是一種緊湊的、傳遞行為的方式。Lambda表達(dá)式本質(zhì)上是為了解決方便的將代碼作為數(shù)據(jù)傳遞的難題。從本質(zhì)上講lambda表達(dá)式就是一種將行為參數(shù)化的操作。
在JDK8之前,需要利用匿名內(nèi)部類來(lái)實(shí)現(xiàn)的傳遞行為的操作,現(xiàn)在可以用lambda表達(dá)式來(lái)實(shí)現(xiàn)了。 從編碼的角度講,lambda表達(dá)式是一個(gè)代碼塊,以及必須傳入代碼的變量規(guī)范。
由于規(guī)范基本一致,所以Java中的lambda表達(dá)式和JavaScript中的在使用上幾乎完全一樣。所差別的只是胖箭頭和瘦箭頭而已。當(dāng)然由于語(yǔ)言特性的問(wèn)題,兩種lambda表達(dá)式的實(shí)際差距還是很大的,這種差距表現(xiàn)在:在Java中,lambda表達(dá)式本身是有類型的。也就是說(shuō)要傳遞的行為必須是有類型的,這種類型就是函數(shù)接口。
除了傳參之外,lambda表達(dá)式也可以出現(xiàn)在賦值符號(hào)的右邊。
lambda表達(dá)式的語(yǔ)法: lambda表達(dá)式由參數(shù)、箭頭、表達(dá)式組成。
(parameters) -> expression //此處行為為表達(dá)式,這里隱含了return語(yǔ)句。
或者
(parameters) -> { statements; } //此處行為為語(yǔ)句,需要返回時(shí)要手寫return語(yǔ)句。
1,如果代碼無(wú)法在一個(gè)表達(dá)式中完成,可以像寫方法一樣把代碼放在大括號(hào)中。只有一行代碼的Lambda表達(dá)式也可以使用大括號(hào)。
()->{
...
}
2,沒有參數(shù)時(shí),也要提供一個(gè)空的小括號(hào)。如果只有一個(gè)參數(shù),而且這個(gè)參數(shù)的類型可以推導(dǎo),也可以省略小括號(hào)。Lambda表達(dá)式也可以包含多個(gè)參數(shù)
(param)->expression
param->expression
3,大部分情況中,無(wú)需指定lambda表達(dá)式的返回類型。具體的返回類型可以由上下文推斷得出。
這種類型推導(dǎo)實(shí)際上是Java7中的目標(biāo)類型推斷的擴(kuò)展。在Java7中以下代碼是合法的,這是泛型的又一個(gè)升級(jí)。
Map map=new HashMap<>(); //不用聲明HashMap的中的鍵值對(duì)類型,系統(tǒng)可以通過(guò)Map的相關(guān)類型推斷出來(lái)。
這就是所謂的類型推斷。
4,lambda表達(dá)式中只在某些分支返回值,另一個(gè)些分支不返回值是不合法的。
5,與JavaScript相同,lambda表達(dá)式只有一個(gè)入?yún)r(shí),可以省略小括號(hào)。
example:
BinaryOperator add=(x,y)->x+y; //創(chuàng)建一個(gè)函數(shù),用來(lái)計(jì)算x和y相加的結(jié)果。
注意:add不是兩個(gè)數(shù)字的和,而是將兩個(gè)數(shù)字加相的那行代碼。
System.out.println(add.apply(1l,2l)); //打印3
解析:binaryOperator是一個(gè)接口,其含義進(jìn)行一次兩數(shù)據(jù)的某種操作,并返回這個(gè)操作的結(jié)果。其抽象方法來(lái)自父接口BiFunction。BiFunction接口是不同數(shù)據(jù)類型的操作、而binaryOperator接口是針對(duì)相同類型數(shù)據(jù)的操作。
public interface BiFunction {
R apply(T t, U u);
}
public interface BinaryOperator extends BiFunction{}
需要注意的是: Lambda表達(dá)式中引用的在表達(dá)式之外定義的局部變量必須是final或既成事實(shí)上的final變量。 這個(gè)約束性的規(guī)定來(lái)源于java 8之前的匿名內(nèi)部類,java 8放寬了這個(gè)規(guī)定,既局部變量可以不加final關(guān)鍵字,但依然不能給該變量多次賦值。
函數(shù)接口
函數(shù)接口是只有一個(gè)抽象方法的接口,用作Lambda表達(dá)式的類型。也就是說(shuō)所謂的Lambda表達(dá)式對(duì)應(yīng)的其實(shí)就是函數(shù)接口。 java8提供@FunctionalInterface注解函數(shù)接口,當(dāng)然這個(gè)注解是非必須的,只要接口符合函數(shù)接口的標(biāo)準(zhǔn)(即只包含一個(gè)抽象方法的接口)即可。 函數(shù)式接口的抽象方法簽名基本上就是Lambda表達(dá)式的簽名,這種抽象方法叫作函數(shù)描述符。 幾個(gè)重要的函數(shù)式接口,它們都位于java.util.function包中:
Predicate接口
@FunctionalInterface
public interface Predicate{
boolean test(T t);
}
Consumer接口
@FunctionalInterface
public interface Consumer{
void accept(T t);
}
BiConsumer接口
@FunctionalInterface
public interface BiConsumer {
void accept(T t, U u);
}
Function接口
@FunctionalInterfac
public interface Function{
R apply(T t);
}
為避免在使用原始類型時(shí)進(jìn)行自動(dòng)拆、裝箱操作,jdk8提供了以上函數(shù)式接口的原始類型版本。
IntPredicate、DoublePredicate等
Supplier接口
@FunctionalInterface
public interface Supplier {
T get();
}
BinaryOperator接口
BinaryOprator接口繼承自BiFunction接口,其接口方法源型如下:
R apply(T t, U u);
方法引用
方法引用是lambda表達(dá)式的一種簡(jiǎn)化寫法。當(dāng)要調(diào)用的方法是一個(gè)已經(jīng)存在的方法時(shí)可以使用方法引用。使用方法引用替換整個(gè)Lambda表達(dá)式。 語(yǔ)法為:左邊是容器(可以是類名,實(shí)例名),中間是"::",右邊是相應(yīng)的方法名(不帶小括號(hào))。
ObjectReference::methodName
一般方法的引用格式:
調(diào)用靜態(tài)方法,ClassName::methodName。如 Person::compareByAge調(diào)用實(shí)例方法,Instance::methodName。如System.out::println;調(diào)用參數(shù)的實(shí)例方法,ClassName::methodName。Object::equals;調(diào)用構(gòu)造方法,ClassName::new 。如:Person::new;注意:
當(dāng)匿名方法有參數(shù)并且lambda表達(dá)式就是調(diào)用參數(shù)中的方法的時(shí)候,可以直接用參數(shù)的類名做為容器。如下:
List collected=Stream.of("a","b","hello")
.map(string->string.toUpperCase)
.collect(Collectors.toList());
//注意這里使用了方法引用
List collected=Stream.of("a","b","hello")
.map(String::toUpperCase)
.collect(Collectors.toList());
本質(zhì)上講:方法引用是Lambda表達(dá)式的快捷寫法。當(dāng)這個(gè)Lambda表達(dá)式代表的只是直接調(diào)用某個(gè)已經(jīng)存在的方法時(shí)使用。
可以把方法引用當(dāng)作針對(duì)僅涉及單一方法的Lambda的語(yǔ)法糖。
forExample:
public class LambdaExample {
public static void main(String[] args) {
List names = Arrays.asList("peter", "anna", "mike", "xenia");
/*匿名內(nèi)部類的方式
Collections.sort(names, new Comparator() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
*/
/*lambda表達(dá)式
Collections.sort(names, (a,b) -> {
return b.compareTo(a);
});
*/
//簡(jiǎn)易寫法
Collections.sort(names, (a, b) -> b.compareTo(a));
//進(jìn)一步簡(jiǎn)寫
Collections.sort(names,String::compareTo);
for(String s:names){
System.out.println(s);
}
}
}
public class ThreadExample {
public static void main(String[] args) {
Thread thread=new Thread(()->{
for(int i=0;i<10;i++){
System.out.println(i);
}
});
thread.start();
}
}
每一個(gè)lambda表達(dá)式都對(duì)應(yīng)一個(gè)類型,通常是接口類型。而“函數(shù)式接口”是指僅僅只包含一個(gè)抽象方法的接口,每一個(gè)該類型的lambda表達(dá)式都會(huì)被匹配到這個(gè)抽象方法。因?yàn)槟J(rèn)方法不算抽象方法,所以你也可以給你的函數(shù)式接口添加默認(rèn)方法。 我們可以將lambda表達(dá)式當(dāng)作任意只包含一個(gè)抽象方法的接口類型,確保你的接口一定達(dá)到這個(gè)要求,你只需要給你的接口添加 @FunctionalInterface 注解,編譯器如果發(fā)現(xiàn)你標(biāo)注了這個(gè)注解的接口有多于一個(gè)抽象方法的時(shí)候會(huì)報(bào)錯(cuò)的。
@FunctionalInterface
interface Converter {
T convert(F from);
}
Converter converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted); // 123
下一篇lambda2講解具體的API語(yǔ)法,以及應(yīng)用場(chǎng)景。
Java8中l(wèi)ambda表達(dá)式的語(yǔ)法,別人都會(huì)的,你還不會(huì)嗎?「二」
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的变量不合法的表达式JAVA_Java8中lambda表达式的语法,别人都会的,你还不会吗?「一」...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 虚拟机安装rsync服务器配置,虚拟机安
- 下一篇: java textfield赋值_Jav