JDK新特性-Lambda表達(dá)式的神操作
一、Lambda表達(dá)式的介紹
- Lambda表達(dá)式是 Java8 中最重要的新功能之一。使用 Lambda 表達(dá)式可以替代只有一個抽象函數(shù)的接口實現(xiàn),告別匿名內(nèi)部類,代碼看起來更簡潔易懂。Lambda表達(dá)式同時還提升了對集合、框架的迭代、遍歷、過濾數(shù)據(jù)的操作。
- lambda表達(dá)式可以替代只有一個抽象函數(shù)的接口實現(xiàn),告別匿名內(nèi)部類,代碼看起來更簡潔易懂
- lambda表達(dá)式同時還提升了對集合、框架的迭代、遍歷、過濾數(shù)據(jù)的操作
- lambda可以極大的減少代碼冗余,同時代碼的可讀性要好過冗長的內(nèi)部類,匿名類
例如以前我們使用匿名內(nèi)部類來實現(xiàn)代碼:
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- System.out.println("running1 .....");
- }
- };
- runnable.run();
使用lambda表達(dá)式實現(xiàn)更簡潔的代碼:
- Runnable runnable3 = ()-> System.out.println("running2....");
- runnable3.run();
lambda表達(dá)式語法:
- LambdaParameters -> LambdaBody
在這里插入圖片描述
args -> expr或者(object … args)-> {函數(shù)式接口抽象方法實現(xiàn)邏輯}
1、()參數(shù)的個數(shù),根據(jù)函數(shù)式接口里面抽象的參數(shù)個數(shù)來決定,當(dāng)參數(shù)只有一個的時候,()可以省略
2、當(dāng)expr邏輯非常簡單的時候,{}和return可以省略
案例說明:
- public static void main(String[] args) throws Exception {
- Callable<String> c1 = new Callable() {
- @Override
- public String call() throws Exception {
- return "muxiaonong";
- }
- };
- System.out.println(c1.call());
- Callable<String> c2 = ()->{return "muxiaonong2";};
- System.out.println(c2.call());
- //邏輯很簡單的時候省略 {} 和 return
- Callable<String> c3 = ()->"muxiaonong3";
- System.out.println(c3.call());
- }
二、Lambda表達(dá)式的特點
- 函數(shù)式編程
- 參數(shù)類型自動推斷
- 代碼量少,簡潔
三、Lambda表達(dá)式案例
實現(xiàn)方式列表:
- ()->{}
- ()->{System.out.println(1);}
- ()->System.out.println(1)
- ()->{return 100;}
- ()->100
- ()->null
- (int x)->{return x+1;}
- (int x)->x+1
- (x)->x+1
- x->x+1
案例1:線程實現(xiàn)方式:
- public static void main(String[] args) {
- //匿名內(nèi)部類方式
- new Thread(new Runnable() {
- @Override
- public void run() {
- System.out.println("runing1..........");
- }
- });
- //Lambda表達(dá)式方式
- new Thread(() -> {System.out.println("runing2.....");}).start();
- }
案例2:集合遍歷實現(xiàn)方式
- public static void main(String[] args) {
- List<String> list = Arrays.asList("java","python","scala","javascript");
- //普通匿名內(nèi)部類方式
- Collections.sort(list, new Comparator<String>() {
- @Override
- public int compare(String o1, String o2) {
- return o1.length() - o2.length();
- }
- });
- //Lambda方式
- Collections.sort(list,(a,b) -> a.length() - b.length());
- list.forEach(System.out::println);
- }
四、Lambda表達(dá)式的應(yīng)用場景
重要的事情說三遍:任何有函數(shù)式接口的地方 * 3
什么是函數(shù)式接口: 只有一個抽象方法(Object類中的方法除外)的接口是函數(shù)式接口
五、Lambda表達(dá)式實際應(yīng)用
5.1 無參實體類模擬
模擬數(shù)據(jù)庫連接層:
- @FunctionalInterface
- public interface StudentDao {
- void insert(Student student);
- }
實體類
- /** @Author mxn
- * @Description 學(xué)生實體類
- * @Date 10:19 2020/11/7
- * @Param
- * @return
- **/
- public class Student {
- }
- public static void main(String[] args) {
- StudentDao sd1 = new StudentDao() {
- @Override
- public void insert(Student student) {
- System.out.println("插入學(xué)生1");
- }
- };
- StudentDao sd2 = (student)->{
- System.out.println("student: "+student);
- };
- StudentDao sd3 = (Student student)-> System.out.println("student3:"+student);
- sd1.insert(new Student()); //輸出 插入學(xué)生1
- sd2.insert(new Student());// 輸出
- sd3.insert(new Student());// 輸出
- }
5.2 有參實體類模擬
實體類
- /** @Author mxn
- * @Description
- * @Date 10:26 2020/11/7
- * @Param
- * @return
- **/
- public class Teacher {
- }
接口模擬層
- @FunctionalInterface
- public interface TeacherDao {
- int get(Teacher teacher);
- }
實現(xiàn)層
- public static void main(String[] args) {
- TeacherDao td1 = new TeacherDao() {
- @Override
- public int get(Teacher teacher) {
- return 1;
- }
- };
- TeacherDao td2 = (teacher)->{return 2;};
- TeacherDao td3 = (Teacher teacher)->{return 3;};
- TeacherDao td4 = (teacher)->4;
- TeacherDao td5 = (Teacher teacher)->5;
- System.out.println(td1.get(new Teacher()));//輸出 1
- System.out.println(td2.get(new Teacher()));//輸出 2
- System.out.println(td3.get(new Teacher()));//輸出 3
- System.out.println(td4.get(new Teacher()));//輸出 4
- System.out.println(td5.get(new Teacher()));//輸出 5
- }
六、函數(shù)式接口
Supplier:代表一個輸出
Consumer:代表一個輸入
BiConsumer:代表兩個輸入
Function:代表一個輸入,一個輸出(一般輸入和輸出是不同類型的)
UnaryOperator:代表一個輸入,一個輸出(輸入和輸出是相同類型的)
BiFunction:代表兩個輸入,一個輸出(一般輸入和輸出是不同類型的)
BinaryOperator:代表兩個輸入,一個輸出(輸入和輸出是相同類型的)
在Java中提供了一系列的函數(shù)式接口,用來接受后續(xù)傳入的邏輯,但是對輸入和輸出有要求
6.1 Supplier:代表一個輸出
- Supplier<String> s1 = ()->{return "muxiaonong";};
- Supplier<String> s2 = ()->"muxiaonong2";
- System.out.println(s1.get());//輸出 muxiaonong
- System.out.println(s2.get());//輸出 muxiaonong2
6.2 Consumer:代表一個輸入
- Consumer<String> c11 = (str) -> System.out.println(str);
- c11.accept("beijing");//輸出 beijing
6.3 BiConsumer:代表兩個輸入
- BiFunction<String,String,Integer> bf = (a,b)->a.length()+b.length();
- System.out.println(bf.apply("大吉大利", "今晚吃雞"));//輸出一個字符串長度 8
6.4 Function:代表一個輸入,一個輸出
- // Function<String,Integer> 用來接收后面的函數(shù)的實現(xiàn),規(guī)定必須有一個輸入(String)有一個輸出(Integer)
- Function<String,Integer> f1 = (str)->{return str.length();};
- System.out.println(f1.apply("abcdefg"));//輸出長度 7
七、方法的引用
方法引用是用來直接訪問類或者實例的已經(jīng)存在的方法或者構(gòu)造方法,方法引用提供了一種引用而不執(zhí)行方法的方式,如果抽象方法的實現(xiàn)恰好可以使用調(diào)用另外一個方法來實現(xiàn),就有可能可以使用方法引用
7.1 方法引用的分類
7.2 靜態(tài)方法引用
靜態(tài)方法引用: 如果函數(shù)式接口的實現(xiàn)恰好可以通過 調(diào)用一個靜態(tài)方法 來實現(xiàn),那么就可以使用靜態(tài)方法引用
- /**
- * @program: lambda
- * @ClassName Test2
- * @description:
- * @author: muxiaonong
- * @create: 2020-10-28 22:15
- * @Version 1.0
- **/
- public class Test2 {
- //無參靜態(tài)方法
- static String put(){
- System.out.println("put.....");
- return "put";
- }
- //有參靜態(tài)方法
- public static void getSize(int size){
- System.out.println(size);
- }
- //有參 有返回值靜態(tài)方法
- public static String toUpperCase(String str){
- return str.toUpperCase();
- }
- //兩個入?yún)?,一個返回值靜態(tài)方法
- public static Integer getLength(String str,String str2){
- return str.length()+str2.length();
- }
- public static void main(String[] args) {
- //無參靜態(tài)方法-普通調(diào)用
- System.out.println(put());//輸出put
- //無參靜態(tài)方法-原生調(diào)用
- Supplier<String> s1 = ()-> Test2.put();
- System.out.println(s1.get());//輸出put
- //無參靜態(tài)方法-靜態(tài)方法引用
- Supplier<String> s2 = Test2::put;
- System.out.println(s2.get());//輸出put
- //無參靜態(tài)方法-內(nèi)部類調(diào)用
- Supplier<String> s3 = Fun::hehe;
- System.out.println(s3.get()); //輸出hehe
- // 有參靜態(tài)方法-靜態(tài)方法引用
- Consumer<Integer> c1 = Test2::getSize;
- Consumer<Integer> c2 = (size)-> Test2.getSize(size);
- c1.accept(123);
- c2.accept(111);
- //有參有返回值靜態(tài)方法
- Function<String,String> f1 = (str)->str.toUpperCase();
- Function<String,String> f2 = (str)-> Test2.toUpperCase(str);
- Function<String,String> f3 = Test2::toUpperCase;
- Function<String,String> f4 = Test2::toUpperCase;
- System.out.println(f1.apply("abc"));//輸出 ABC
- System.out.println(f2.apply("abc"));//輸出 ABC
- System.out.println(f3.apply("abc"));//輸出 ABC
- System.out.println(f4.apply("abc"));//輸出 ABC
- // 兩個參數(shù) 一個返回值 函數(shù)式接口
- BiFunction<String,String,Integer> bf = (a, b)->a.length()+b.length();
- BiFunction<String,String,Integer> bf2 = Test2::getLength;
- System.out.println(bf2.apply("abc", "def"));//輸出 6
- System.out.println(bf.apply("abc", "def"));//輸出 6
- }
- //內(nèi)部類
- class Fun {
- public static String hehe(){
- return "hehe";
- }
- public static String toUpperCase(String str){
- return str.toUpperCase();
- }
- }
- }
7.3 實例方法引用
實例方法引用: 如果函數(shù)式接口的實現(xiàn)恰好可以通過調(diào)用一個實例的實例方法來實現(xiàn),那么就可以使用實例方法引用
- public class Test3 {
- //實例無參方法
- public String put(){
- return "put...";
- }
- //實例有參方法
- public void getSize(int size){
- System.out.println("size:"+size);
- }
- //實例有參有返回值方法
- public String toUpperCase(String str){
- return str.toUpperCase();
- }
- public static void main(String[] args) {
- //實例無參方法返回-普通調(diào)用
- System.out.println(new Test3().put());//輸出 put...
- Supplier<String> s1 = ()->new Test3().put();
- Supplier<String> s2 = ()->{return new Test3().put();};
- Supplier<String> s3 = new Test3()::put;
- System.out.println(s1.get());//輸出 put...
- System.out.println(s2.get());//輸出 put...
- System.out.println(s3.get());//輸出 put...
- //唯一的創(chuàng)建一個test3對象
- Test3 test = new Test3();
- Consumer<Integer> c1 = (size)->new Test3().getSize(size);
- Consumer<Integer> c2 = new Test3()::getSize;
- Consumer<Integer> c3 = test::getSize;
- c1.accept(123);//輸出 size:123
- c2.accept(123);//輸出 size:123
- c3.accept(123);//輸出 size:123
- Function<String,String> f1 = (str)->str.toUpperCase();
- Function<String,String> f2 = (str)->test.toUpperCase(str);
- Function<String,String> f3 = new Test3()::toUpperCase;
- Function<String,String> f4 = test::toUpperCase;
- System.out.println(f1.apply("abc"));//輸出 ABC
- System.out.println(f2.apply("abc"));//輸出 ABC
- System.out.println(f3.apply("abc"));//輸出 ABC
- System.out.println(f4.apply("abc"));//輸出 ABC
- }
- }
7.4 對象方法引用
對象方法引用: 抽象方法的第一個參數(shù)類型剛好是實例方法的類型,抽象方法剩余的參數(shù)恰好可以當(dāng)做實例方法的參數(shù)。如果函數(shù)式接口的實現(xiàn)能由上面說的實例方法調(diào)用來實現(xiàn)的話,那么就可以使用對象方法引用
- /** @Author mxn
- * @Description //TODO 對象方法引用
- * @Date 14:26 2020/11/7
- * @Param
- * @return
- **/
- public class Test4 {
- public static void main(String[] args) {
- Consumer<Too> c1 = (too)->new Too().foo();
- c1.accept(new Too());//輸出 foo
- Consumer<Too> c2 = (Too too) ->new Too2().foo();
- c2.accept(new Too());//輸出 foo---too2
- Consumer<Too> c3 = Too::foo;
- c3.accept(new Too());//輸出 foo
- BiConsumer<Too2,String> bc = (too2,str)->new Too2().show(str);
- BiConsumer<Too2,String> bc2 = Too2::show;
- bc.accept(new Too2(),"abc");
- bc2.accept(new Too2(),"def");
- BiFunction<Exec,String,Integer> bf1 = (e,s)->new Exec().test(s);
- bf1.apply(new Exec(),"abc");
- BiFunction<Exec,String,Integer> bf2 = Exec::test;
- bf2.apply(new Exec(),"def");
- }
- }
- class Exec{
- public int test(String name){
- return 1;
- }
- }
- class Too{
- public Integer fun(String s){
- return 1;
- }
- public void foo(){
- System.out.println("foo");
- }
- }
- class Too2{
- public Integer fun(String s){
- return 1;
- }
- public void foo(){
- System.out.println("foo---too2");
- }
- public void show(String str){
- System.out.println("show ---too2"+str);
- }
- }
7.5 構(gòu)造方法引用
構(gòu)造方法引用: 如果函數(shù)式接口的實現(xiàn)恰好可以通過調(diào)用一個類的構(gòu)造方法來實現(xiàn),那么就可以使用構(gòu)造方法引用
- /** @Author mxn
- * @Description //TODO 構(gòu)造方法引用
- * @Date 14:27 2020/11/7
- * @Param
- * @return
- **/
- public class Test5 {
- public static void main(String[] args) {
- Supplier<Person> s1 = ()->new Person();
- s1.get();//輸出 調(diào)用無參的構(gòu)造方法
- Supplier<Person> s2 = Person::new;
- s2.get();//輸出 調(diào)用無參的構(gòu)造方法
- Supplier<List> s3 = ArrayList::new;
- Supplier<Set> s4 = HashSet::new;
- Supplier<Thread> s5 = Thread::new;
- Supplier<String> s6 = String::new;
- Consumer<Integer> c1 = (age)->new Account(age);
- Consumer<Integer> c2 = Account::new;
- c1.accept(123);// 輸出 age 參數(shù)構(gòu)造123
- c2.accept(456);//輸出 age 參數(shù)構(gòu)造456
- Function<String,Account> f1 = (str)->new Account(str);
- Function<String,Account> f2 = Account::new;
- f1.apply("abc");//輸出 str 參數(shù)構(gòu)造abc
- f2.apply("def");//輸出 str 參數(shù)構(gòu)造def
- }
- }
- class Account{
- public Account(){
- System.out.println("調(diào)用無參構(gòu)造方法");
- }
- public Account(int age){
- System.out.println("age 參數(shù)構(gòu)造" +age);
- }
- public Account(String str){
- System.out.println("str 參數(shù)構(gòu)造" +str);
- }
- }
- class Person{
- public Person(){
- System.out.println("調(diào)用無參的構(gòu)造方法");
- }
- }
八、小結(jié)
- Java8 引入 Lambda表達(dá)式是接收了函數(shù)式編程語言的思想,和指令式編程相比,函數(shù)式編程強(qiáng)調(diào)函數(shù)的計算比指令的執(zhí)行重要。引入 Lambda表達(dá)式是接收了函數(shù)式編程語言的思想,和指令式編程相比,函數(shù)式編程強(qiáng)調(diào)函數(shù)的計算比指令的執(zhí)行重要。引入 Lambda表達(dá)式是接收了函數(shù)式編程語言的思想,和指令式編程相比,函數(shù)式編程強(qiáng)調(diào)函數(shù)的計算比指令的執(zhí)行重要。
- lambda表達(dá)式可以使代碼看起來簡潔,但一定程度上增加了代碼的可讀性以及調(diào)試的復(fù)雜性,所以在使用時應(yīng)盡量是團(tuán)隊都熟悉使用,要么干脆就別用,不然維護(hù)起來是件較痛苦的事,今天的小知識就到這里了,有問題的小伙伴可以在下方進(jìn)行留言,大家加油!