一、lambda初探
lambda可以是java_8出來新特性侣灶,可以使代碼更加緊湊以及簡(jiǎn)潔才漆,增加可讀性乾胶,下面簡(jiǎn)單的幾個(gè)例子我們可以來感受下java lambda的相關(guān)魅力
//例子1
//傳統(tǒng)寫法
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("你好世界");
}
}).start();
//增加lambda以后的寫法
new Thread(()->System.out.println("你好世界")).start();//省略了內(nèi)部類,內(nèi)部抽象方法谴轮。
//例子2
ArrayList<String> list = new ArrayList<>();
list.add("hello");
list.add("world");
list.add("java");
list.add("python");
list.add("Android");
list.forEach((str)->{
System.out.println(str);
});
//傳統(tǒng)寫法狂巢,注意list.forEach方法是在java 8之后新出來的方法,對(duì)應(yīng)的map.forEach()
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
//優(yōu)化
list.forEach((str)->System.out.println(str)); //省略了內(nèi)部類和抽象方法
//再次優(yōu)化
list.forEach(System.out::println); //省略了相關(guān)型參數(shù)
//例子3
List<Person> personList = Arrays.asList(
new Person("張三",22),
new Person("王五",25),
new Person("趙六",29),
new Person("李二麻子",34),
new Person("小馬",18)
);
//傳統(tǒng)的排序
Collections.sort(personList, new Comparator<Person>() {
@Override
public int compare(Person person, Person t1) {
return person.getAge() - t1.getAge();
}
});
//lambda排序
Collections.sort(personList,(t1,t2)-> t1.getAge() - t2.getAge()); //返回值去掉了{(lán)},;和return.
personList.forEach(System.out::println); //進(jìn)行相應(yīng)遍歷
二书聚、lambda定義與語(yǔ)法
定義 : lambda表達(dá)式是函數(shù)式編程風(fēng)格,為了給SAM(Single Abstract Method(單一抽象方法))類型接口變量和形參賦值的一種語(yǔ)法藻雌;隱含了匿名內(nèi)部類創(chuàng)建過程雌续,并替代了原來匿名內(nèi)部類的對(duì)象給函數(shù)式接口(SAM接口)的變量或形參賦值的形式。注意該內(nèi)部類只能有一個(gè)方法胯杭。
語(yǔ)法格式:(形參列表)->{lambda體}
- (形參列表)就是SAM接口的抽象方法的形參列表驯杜。如果類型已知,獲取的類型可以推斷做个,數(shù)據(jù)類型可以省略鸽心;形參只有一個(gè)可以省略相應(yīng)形參類型,和形參括號(hào)居暖,如果沒有參數(shù)顽频,那么空括號(hào)不能刪除。
- {Lambda體} 就是實(shí)現(xiàn)SAM接口抽象方法的方法體太闺。如果lambda只有一句糯景,可以省略“{}”,相應(yīng)的“省骂;”也需要省略蟀淮,如果沒有省略那么“{}”,“钞澳;”都不省略怠惶;如果返回是一句返回語(yǔ)句,那么"return","{}",";“都可以省略轧粟。
- -> 稱為L(zhǎng)ambda操作符
三策治、lambda形式
- 無參數(shù),無返回 ()->打印
- 有參數(shù)逃延,無返回 (T t...)->打印
- 無參數(shù)览妖,有返回 ()-> return
- 有參數(shù),有返回 (T t...) ->return
四揽祥、lambda典型接口
1. 消費(fèi)型接口
接口類 | 抽象方法 | 說明 |
---|---|---|
Consumer<T> | accept(T t) | 傳遞一個(gè)參數(shù)讽膏,無返回值 |
BiConsumer<T,U> | accept(T t,U u) | 傳遞兩個(gè)參數(shù),無返回值 |
DoubleConsumer | accept(double value) | 傳遞一個(gè)double值拄丰,無返回值 |
IntConsumer | accept(int value) | 傳遞一個(gè)int值府树,無返回值 |
LongConsumer | accept(long value) | 傳遞一個(gè)long值俐末,無返回值 |
ObjDoubleConsumer<T> | accept(T t,double value) | 傳遞一個(gè)對(duì)象,和double類型值奄侠,無返回值 |
ObjIntConsumer<T> | accept(T t,double value) | 傳遞一個(gè)對(duì)象卓箫,和Int類型值,無返回值 |
ObjLongConsumer<T> | accept(T t,double value) | 傳遞一個(gè)對(duì)象垄潮,和Long類型值烹卒,無返回值 |
總結(jié) : 1. 消費(fèi)型接口都是以“consumer”單詞為結(jié)尾
? 2 . Bi(Binary)開頭都是傳遞兩個(gè)參數(shù)
? 3. xxConsumer,前面的xx代表形參類型
2.供給型接口
接口類 | 抽象方法 | 說明 |
---|---|---|
Supplier<T> | T get() | 無參數(shù),有返回值 |
BooleanSupplier | boolean getAsBoolean() | 無參數(shù)弯洗,返回boolean值 |
DoubleSupplier | double getAsDouble() | 無參數(shù)旅急,返回Double值 |
IntSupplier | int getAsInt() | 無參數(shù),返回int值 |
LongSupplier | long getAsLong() | 無參數(shù)牡整,返回long值 |
總結(jié) 1.供給型接口以“Supplier”單詞結(jié)尾藐吮;2.xxSupplier說明返回xx類型結(jié)果 ;3.供給型接口的抽象方法都是無參數(shù)的
3. 判斷型接口
接口類 | 抽象方法 | 說明 |
---|---|---|
Predicate<T> | boolean test(T t) | 有一個(gè)參數(shù)逃贝,有返回值 |
BiPredicate<T,U> | boolean test(T t,U u) | 有兩個(gè)參數(shù)谣辞,有返回值 |
DoublePredicate | boolean test(double value) | 有一個(gè)double參數(shù),有返回值 |
IntPredicate | boolean test(int value) | 有一個(gè)int 參數(shù)沐扳,有返回值 |
LongPredicate | boolean test(long value) | 有一個(gè)long參數(shù)泥从,有返回值 |
總結(jié): 1. 判斷型接口以“predicate”結(jié)尾 ; 2.判斷型接口抽象方法的返回值類型是固定的沪摄,是boolean;3xxPredicatte歉闰,說明形參是xx類型的
4. 功能型接口
接口類 | 抽象方法 | 說明 |
---|---|---|
Function<T,R> | R apply(T t) | 有一個(gè)參數(shù),有返回值 |
UnaryOperator<T> | T apply(T t) | 有一個(gè)參數(shù)卓起,有返回值和敬,且參數(shù)類型和返回值類型一致 |
DoubleFunction<R> | R apply(double value) | double參數(shù),返回R類型對(duì)象 |
IntFunction<R> | R apply(int value) | int參數(shù)戏阅,返回R類型對(duì)象 |
LongFunction<R> | R apply(long value) | long 參數(shù)昼弟,返回R類型對(duì)象 |
ToDoubleFunction<T> | double apply(T t) | T類型對(duì)象參數(shù),返回double類型數(shù)據(jù) |
ToIntFunction<T> | int apply(T t) | T類型對(duì)象參數(shù)奕筐,返回int類型數(shù)據(jù) |
ToLongFunction<T> | long apply(T t) | T類型對(duì)象參數(shù)舱痘,返回long類型數(shù)據(jù) |
DoubleToIntFunction | int applyAsInt(double value) | double參數(shù),int類型返回?cái)?shù)據(jù) |
DoubleToLongFunction | long applyAsInt(double value) | double參數(shù)离赫,long類型返回?cái)?shù)據(jù) |
IntToDoubleFunction | double applyAsInt(int value) | int 參數(shù)芭逝,double類型返回?cái)?shù)據(jù) |
IntToLongFunction | long applyAsInt(int value) | int 參數(shù),long類型返回?cái)?shù)據(jù) |
LongToDoubleFunction | double applyAsInt(long value) | long參數(shù)渊胸,double類型返回?cái)?shù)據(jù) |
LongToIntFunction | int applyAsInt(long value) | long 參數(shù)旬盯,int類型返回?cái)?shù)據(jù) |
DoubleUnaryOperator | double applyasDouble(double orperand) | double參數(shù),double返回?cái)?shù)據(jù) |
IntUnaryOperator | int applyasDouble(int orperand) | int 參數(shù),int 返回?cái)?shù)據(jù) |
LongUnaryOperator | long applyasDouble(long orperand) | long 參數(shù)胖翰,long返回?cái)?shù)據(jù) |
BiFunction<T,U,R> | R apply(T t,U u) | T,U參數(shù)接剩,R返回 |
BinaryOperator<T> | T apply(T t,T u) | T,T參數(shù),T返回 |
ToDoubleBiFunction<T萨咳,U> | double applyAsDouble(T t,U u) | T,U參數(shù)懊缺,double返回 |
ToIntBiFunction<T,U> | int applyAsDouble(T t,U u) | T,U參數(shù)培他,int 返回 |
ToLongBiFunction<T鹃两,U> | long applyAsDouble(T t,U u) | T,U參數(shù),long返回 |
DoubleBinaryOperator | double applyAsDouble(double t1,double t2) | double,double參數(shù)舀凛,double返回 |
IntBinaryOperator | int applyAsDouble(int t1,int t2) | int ,int 參數(shù)怔毛,int 返回 |
LongBinaryOperator | long applyAsDouble(longt1,longt2) | long,long參數(shù),long返回 |
總結(jié):
- 以Unary開頭腾降,表示一元,泛型的類型只有一個(gè)碎绎,形參和返回值都是一種類型
- xxFunction螃壤,說明形參類別是xx類型
- toxxFunction 說明返回值類型是xx類型
- xxToyyfunction 說明形參的類型是xx類型的,返回值類型yy類型
- xxUnary開頭筋帖,表示一元奸晴,形參和返回都是xx
- Bi開頭,表示二元日麸,形參類型是2個(gè)
- BinaryOperator既是Bi開頭連個(gè)形參寄啼,又是Oprator結(jié)尾,表示形參和返回類型是一致的
- toXXBi開頭的代箭,表示返回值類型是xx,并且形參是兩個(gè)
- xxBinaryOPerator墩划,表示兩個(gè)形參,又是Operator結(jié)尾嗡综,表示形參和返回值類型是一樣的
五.接口舉例
1.消費(fèi)型接口
ArrayList<String> list = new ArrayList<>();
list.add("hello");
list.add("world");
list.add("java");
list.add("python");
list.add("Android");
list.forEach((str)->{
System.out.println(str);
});
//Consumer接口乙帮,參數(shù)為String類型
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
//用lambda表示
list.forEach(str->{
System.out.println(str);
});
2.供給型接口
//new Supplier<T> get()抽象方法,返回一個(gè)double類型數(shù)據(jù)
Stream<Double> stream = Stream.generate(new Supplier<Double>() {
@Override
public Double get() {
return Math.random();
}
});
//優(yōu)化為lambda表達(dá)式
Stream.generate(()-> Math.random());
3. 判斷型接口
ArrayList<Person> personList = new ArrayList<>();
personList.add( new Person("張三",22));
personList.add( new Person("王五",25));
personList.add( new Person("趙六",29));
personList.add(new Person("李二麻子",34));
personList.add( new Person("小馬",18));
//Predicate接口极景,其中參數(shù)是一個(gè)person對(duì)象察净,返回值為boolean
// personList.removeIf(new Predicate<Person>() {
// @Override
// public boolean test(Person person) {
// return person.getAge() > 25;
// }
// });
//優(yōu)化為lambda樣式
personList.removeIf(p->p.getAge() > 25);
personList.forEach(System.out::println);
返回結(jié)果:
Person{name='張三', age=22}
Person{name='王五', age=25}
Person{name='小馬', age=18}
4. 功能型接口
//例子1.
ArrayList<Person> personList = new ArrayList<>();
personList.add( new Person("張三",22));
personList.add( new Person("王五",25));
personList.add( new Person("趙六",29));
personList.add(new Person("李二麻子",34));
personList.add( new Person("小馬",18));
//功能型接口,參數(shù)為person,返回為person
personList.replaceAll(new UnaryOperator<Person>() {
@Override
public Person apply(Person person) {
if(person.getAge() > 25)
person.setAge(30);
return person;
}
});
personList.forEach(System.out::println);
打印結(jié)果:
Person{name='張三', age=22}
Person{name='王五', age=25}
Person{name='趙六', age=30}
Person{name='李二麻子', age=30}
Person{name='小馬', age=18}
//例2
HashMap<String,Person> map = new HashMap<>();
map.put("張三",new Person("張三",22));
map.put("王五",new Person("王五",25));
map.put("趙六",new Person("趙六",29));
map.put("李二麻子",new Person("李二麻子",34) );
map.put("小馬",new Person("小馬",18) );
//參數(shù)為string,person,返回為person
map.replaceAll(new BiFunction<String, Person, Person>() {
@Override
public Person apply(String s, Person person) {
if(person.getAge() > 25)
person.setAge(30);
return person;
}
});
map.forEach((key,person)->{
System.out.println(key + "::" + person.toString());
});
打印結(jié)果:
張三::Person{name='張三', age=22}
李二麻子::Person{name='李二麻子', age=30}
小馬::Person{name='小馬', age=18}
王五::Person{name='王五', age=25}
趙六::Person{name='趙六', age=30}
六.Lambda方法引用
方法引用使用“::”雙冒號(hào)組成操作符來指定方法盼樟。方法引用后氢卡,參數(shù)會(huì)自動(dòng)傳遞。
-
類的構(gòu)造器引用 ArrayList::new ,String[] ::new
Arrays.asList("a","b","c").stream().toArray(String[]::new); //轉(zhuǎn)變?yōu)閿?shù)組
-
類的靜態(tài)方法引用 Stirng::valueOf,Integer::value of,
Stream.of("1", "2","3").map(Integer::valueOf).forEach(System.out::println);
-
類的實(shí)例方法應(yīng)用 String::length,Person::getName
Stream.of(new Person("張三",22), new Person("王五",25),new Person("趙六",29)) .map(Person::getAge).forEach(System.out::println);
對(duì)象的實(shí)例方法應(yīng)用Sting::length,person::getName;
七.自定義SAM接口
聲明接口晨缴,只能包含一個(gè)抽象方法译秦,必須給這個(gè)接口添加@FunctionalInterface
@FunctionalInterface
public interface IntCalc {
int cal(int a,int b);
}
public static void getProduct(int a,int b,IntCalc tools){
int result = tools.cal(a,b);
System.out.println("結(jié)果:" +result);
}
//調(diào)用該方法,其中方法該接口作為參數(shù)傳入,相當(dāng)于傳入了該操作方法體诀浪。
getProduct(1,2,(a,b) -> a+ b); //
打印結(jié)果:
結(jié)果:3
八.結(jié)語(yǔ)
本文是根據(jù)尚硅谷柴林燕老師講授整理而來棋返,同時(shí)參考Java基礎(chǔ)系列-Lambda