Java8新特性2:Lambda表达式和方法引用

回顾之前《JavaSE-23.3》:
https://www.cnblogs.com/yppah/p/14875254.html
https://www.cnblogs.com/yppah/p/14875479.html
https://www.cnblogs.com/yppah/p/14875492.html
https://www.cnblogs.com/yppah/p/14875500.html
https://www.cnblogs.com/yppah/p/14875507.html


1. 什么是lambda表达式

Lambda 表达式(lambda expression)是一个匿名函数,简化我们调用匿名函数的过程。

Lambda好处: 简化我们匿名内部类的调用。

Lambda+方法引入 代码变得更加精简。

package com.yppah.service;

/**
 * @Author: haifei
 * @Date: 2022/7/20 19:35
 */
public interface OrderService {

    void get();
    /**
     * 如果需要使用到OrderService接口
     * 接口是无法new、可以通过匿名内部类new
     */

}

package com.yppah.myLambda;

import com.yppah.service.OrderService;

/**
 * @Author: haifei
 * @Date: 2022/7/20 19:44
 */
public class Test02 {

    public static void main(String[] args) {
        /*// 通过匿名内部类创建一个接口的子类,用父类(接口)接收
        // 通过匿名内部类的方式调用接口中的方法
        OrderService orderService = new OrderService() {
            @Override
            public void get() { //匿名内部类
                System.out.println("get");
            }
        };
        orderService.get();*/

        // 简写
        /*new OrderService() {
            @Override
            public void get() { //匿名内部类
                System.out.println("get");
            }
        }.get();*/
        ((OrderService) () -> {
            System.out.println("get");
        }).get();

        /*new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+" :run...");
            }
        }).start();*/
        new Thread(() ->
                System.out.println(Thread.currentThread().getName()+" :run...")
        ).start();

    }
}

image-20220720201948956

2. lambda表达式规范

2.1 函数接口定义

Java中使用Lambda表达式的规范,必须是为函数接口

函数接口的定义:在该接口中只能存在一个抽象方法,该接口称作为函数接口

使用Lambda表达式 依赖于函数接口

  • 在函数接口中只能够允许有一个抽象方法
  • 在函数接口中可以定义object类中方法
  • 可以使用默认或者静态方法
  • @FunctionalInterface 表示该接口为函数接口
package com.yppah.myLambda.p2;

/**
 * @Author: haifei
 * @Date: 2022/7/20 20:29
 */
@FunctionalInterface // 函数接口(要求该接口中只能有一个抽象函数,不然注解会报错。但可以有默认或静态方法)
public interface MyFunctionalInterface {
    void get();

    default void add(){
        System.out.println("add");
    }

    // 在函数接口中定义object类中方法
    String toString();
}

2.2 java内置的函数接口

JDK中自带的函数接口:

  • java.lang.Runnable

  • java.util.concurrent.Callable

  • java.security.PrivilegedAction

  • java.util.Comparator

  • java.io.FileFilter

  • java.nio.file.PathMatcher

  • java.lang.reflect.InvocationHandler

  • java.beans.PropertyChangeListener

  • java.awt.event.ActionListener

  • javax.swing.event.ChangeListener


java系统内置哪些函数接口?

image-20221027143429441

image-20221027143505852

2.2.1 消费型接口

Conusmer<T>
       void accept(T t);
BiConusmer<T,U>
       void accept(T t,U u);//增加一种入参类型

2.2.2 供给型接口

Supplier<T>
       void get();

2.2.3 函数型接口

Function<T ,R>
       R apply(T t);
UnaryOperator<T>
       T apply(T t);//入参与返回值类型一致
BiFunction <T ,U,R>
       R apply(T t,U u);//增加一个参数类型
BinaryOperator<T>
       T apply(T t1,T t2);//l两个相同类型入参与同类型返回值
ToIntFunction<T>//限定返回int
ToLongFunction<T>//限定返回long
ToDoubleFunction<T>//限定返回double
IntFunction<R>//限定入参int,返回泛型R
LongFunction<R>//限定入参long,返回泛型R
DoubleFunction<R>//限定入参double,返回泛型R

2.2.4 断言型接口

Predicate<T>
       boolean test(T t);

2.3 Lambda语法

参数列表:()

分隔符:->

方法体:{}

()->{}

2.3.1 无参方法调用

image-20221025144148155

package com.yppah.myLambda.p3;

/**
 * @Author: haifei
 * @Date: 2022/10/25 14:03
 */
@FunctionalInterface
public interface AcanthopanaxInterface {
    void get(); //函数接口必须有且仅有一个抽象方法
}

package com.yppah.myLambda.p3;

import com.yppah.myLambda.p2.MyFunctionalInterface;

/**
 * @Author: haifei
 * @Date: 2022/10/25 14:03
 */
public class Test03 {

    public static void main(String[] args) {
         // 1. 使用匿名内部类调用
        new AcanthopanaxInterface() {
            @Override
            public void get() {
                System.out.println("get");
            }
        }.get();

        // 2. 使用lambda表达式调用
//        ((AcanthopanaxInterface) () -> System.out.println("get")).get();
        AcanthopanaxInterface acanthopanaxInterface = () -> {
            System.out.println("get");
        };
        acanthopanaxInterface.get();
    }
}

2.3.2 带参和返回值

image-20221025150040251

package com.yppah.myLambda.p4;

/**
 * @Author: haifei
 * @Date: 2022/10/25 14:54
 */
@FunctionalInterface
public interface YouShenInterface {
    String get(int i, int j);
}

package com.yppah.myLambda.p4;

/**
 * @Author: haifei
 * @Date: 2022/10/25 14:54
 */
public class Test04 {
    public static void main(String[] args) {
        // 1. 使用匿名内部类调用
        YouShenInterface youShenInterface = new YouShenInterface() {
            @Override
            public String get(int i, int j) {
                return i + "--" + j;
            }
        };
        System.out.println(youShenInterface.get(1, 2));

        // 2. 使用lambda表达式调用
        YouShenInterface youShenInterface2 = (i, j) -> {
            return i+"--"+j;
        };
        System.out.println(        youShenInterface2.get(3, 4));
    }
}

2.3.3 精简语法

  1. 如果方法体中只有一条语句的情况下,可以不需要写{}
  2. 如果方法体中只有一条return的情况下,不需要些{}和return
package com.yppah.myLambda.p5;

import com.yppah.myLambda.p3.AcanthopanaxInterface;
import com.yppah.myLambda.p4.YouShenInterface;

/**
 * @Author: haifei
 * @Date: 2022/10/25 15:04
 */
public class Test05 {
    public static void main(String[] args) {
        // 1-1
        AcanthopanaxInterface acanthopanaxInterface = () -> {
            System.out.println("无参无返回的lambda");
        };
        acanthopanaxInterface.get();

        // 1-2
        ((AcanthopanaxInterface)()->{
            System.out.println("无参无返回的lambda");
        }).get();

        // 2-1
        AcanthopanaxInterface acanthopanaxInterface2 = () -> System.out.println("无参无返回的lambda");
        acanthopanaxInterface2.get();

        // 2-2
        ((AcanthopanaxInterface)()-> System.out.println("无参无返回的lambda")).get();


        // "有参有返回值的1ambda"
        // 3-1
        YouShenInterface youShenInterface = (i, j) -> {
            return i+"-"+j;
        };
        System.out.println(youShenInterface.get(1, 2));

        // 3-2
        YouShenInterface youShenInterface2 = (i, j) -> i+"-"+j;
        System.out.println(youShenInterface2.get(3, 4));

        // 3-3
        String result = ((YouShenInterface) (i, j) -> i + "-" + j).get(5, 6);
        System.out.println(result);
    }
}

image-20221025153345059

2.4 lambda案例

2.4.1 foreach集合遍历

image-20221025154634095

package com.yppah.myLambda.p6;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

/**
 * @Author: haifei
 * @Date: 2022/10/25 15:40
 */
public class Test06 {

    public static void main(String[] args) {
        List<String> arrayList = new ArrayList<>();
        arrayList.add("tom");
        arrayList.add("amy");
        arrayList.add("sam");

        /*arrayList.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });*/
        arrayList.forEach(s -> System.out.println(s));
    }

}

2.4.2 集合排序

image-20221025160220376

package com.yppah.myLambda.p6;

/**
 * @Author: haifei
 * @Date: 2022/10/25 15:47
 */
public class User {

    private String userName;
    private int age;

    public User(String userName, int age) {
        this.userName = userName;
        this.age = age;
    }

    public User() {
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "userName='" + userName + '\'' +
                ", age=" + age +
                '}';
    }
}

package com.yppah.myLambda.p6;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/**
 * @Author: haifei
 * @Date: 2022/10/25 15:47
 */
public class Test07 {

    public static void main(String[] args) {
        List<User> userList = new ArrayList<>();
        userList.add(new User("tom", 22));
        userList.add(new User("amy", 18));
        userList.add(new User("sam", 26));

        /*userList.sort(new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                return o1.getAge()-o2.getAge();
            }
        });*/
        /*userList.forEach((t) -> {
            System.out.println(t.toString());
        });*/

        /*userList.sort((o1, o2) -> {
            return o1.getAge()-o2.getAge();
        });*/
        userList.sort((o1, o2) -> o1.getAge()-o2.getAge());
        userList.forEach(t -> System.out.println(t.toString()));
    }

}

2.4.3 线程调用

image-20221025162248989

package com.yppah.myLambda.p6;

/**
 * @Author: haifei
 * @Date: 2022/10/25 16:03
 */
public class Test08 {

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类-" + Thread.currentThread().getName());
            }
        }).start();

        new Thread(() -> System.out.println("lambda表达式-" + Thread.currentThread().getName())).start();
    }

}

2.5 方法引入

2.5.1 概念和规则

方法引用提供了非常有用的语法,可以直接引用已有的java类或对象的方法或构造器。方法引用其实也离不开Lambda表达式,与lambda联合使用 ,方法引用可以使语言的构造更加紧凑简洁,减少冗余代码。

方法引用提供非常有用的语法,可以直接引用已有的java类或者对象中方法或者构造函数,方法引用需要配合Lambda表达式语法一起使用减少代码的冗余性问题。


//方法引入实际上就是lambda表达式中直接引入方法
//方法引入规范:[引入方法的参数列表、返回类型]与[函数接口数列表、返回类型]必须保持一致

函数接口image-20221027160357024

方法引入image-20221027160428390


image-20221025162510119

image-20221025162637179

2.5.2 静态方法引入

package com.yppah.myLambda.p7;

/**
 * @Author: haifei
 * @Date: 2022/10/27 14:46
 */
@FunctionalInterface
public interface MessageInterface {
    void get(Integer a);
}

package com.yppah.myLambda.p7;

/**
 * @Author: haifei
 * @Date: 2022/10/27 14:43
 */
public class Test09 {

    public static void main(String[] args) {
        // 1. 最原生的匿名内部类调用方式
        MessageInterface messageInterface = new MessageInterface() {
            @Override
            public void get(Integer a) {
                System.out.println("get a: " + a);
            }
        };
        messageInterface.get(1);
        
        
        // 2. lambda表达式改写上述
        MessageInterface messageInterface2 = a->System.out.println("get a: " + a);
        messageInterface2.get(2);
        

        // 新需求:在lambda表达式的方法体中直接引入方法
        MessageInterface messageInterface3 =(a) -> {
            Test09.getStatic(a);
        };
        messageInterface3.get(3);
        
        
        // 精简一下上述代码:方法引入
        // 3. 方法引入写法
        MessageInterface messageInterface4 = Test09::getStatic;
        messageInterface4.get(4);
        //方法引入实际上就是lambda表达式中直接引入方法
        //方法引入规范:[引入方法的参数列表、返回类型]与[函数接口数列表、返回类型]必须保持一致
    }

    public static void getStatic(Integer a) {
        System.out.println("getStatic a: "+ a);
    }
}

image-20221027160711942

2.5.3 实例方法引入

package com.yppah.myLambda.p7;

/**
 * @Author: haifei
 * @Date: 2022/10/27 14:46
 */
@FunctionalInterface
public interface MessageInterface2 {
    String getMsg();
}

package com.yppah.myLambda.p7;

/**
 * @Author: haifei
 * @Date: 2022/10/27 16:08
 */
public class Test10 {

    public static void main(String[] args) {
//        MessageInterface2 messageInterface2 = ()->{return "999"};
        MessageInterface2 mi2 = ()->"999";
        System.out.println(mi2.getMsg()); //999

        Test10 test10 = new Test10();

        MessageInterface2 mi22 = ()->test10.objGet(); //lambda表达式方式
        System.out.println(mi22.getMsg()); //2222

        MessageInterface2 mi23 = test10::objGet; //方法引入方式
        System.out.println(mi23.getMsg()); //2222
    }

    public String objGet() {
        return "2222";
    }
}

2.5.4 构造方法引入

package com.yppah.myLambda.p7;

/**
 * @Author: haifei
 * @Date: 2022/10/27 16:20
 */
public class Message {

    private String msgId;
    private String msgName;

    public Message() {
    }

    @Override
    public String toString() {
        return "Message{" +
                "msgId='" + msgId + '\'' +
                ", msgName='" + msgName + '\'' +
                '}';
    }
}

package com.yppah.myLambda.p7;

/**
 * @Author: haifei
 * @Date: 2022/10/27 14:46
 */
@FunctionalInterface
public interface MessageInterface3 {
    Message getMsg();
}

package com.yppah.myLambda.p7;

/**
 * @Author: haifei
 * @Date: 2022/10/27 16:22
 */
public class Test11 {

    public static void main(String[] args) {
        MessageInterface3 mi3 = ()->{
            return new Message();
        };
        System.out.println(mi3.getMsg()); //Message{msgId='null', msgName='null'}

        //语法
        //函数接口返回类型::new
        MessageInterface3 mi32 = Message::new;
        System.out.println(mi32.getMsg()); //Message{msgId='null', msgName='null'}
    }
}

2.5.5 对象方法引入

package com.yppah.myLambda.p7;

/**
 * @Author: haifei
 * @Date: 2022/10/27 16:40
 */
public interface TestService {
    String get(Test12 test12);
}

package com.yppah.myLambda.p7;

/**
 * @Author: haifei
 * @Date: 2022/10/27 16:40
 */
public class Test12 {
    public static void main(String[] args) {
        // 方式1:匿名内部类
        TestService testService = new TestService() {
            @Override
            public String get(Test12 test12) {
                return test12.objGet();
            }
        };
        System.out.println(testService.get(new Test12())); //nbgeigei

        // 方式2:lambda表达式
        TestService testService2 = test12 -> test12.objGet();
        System.out.println(testService2.get(new Test12())); //nbgeigei

        // 方式3:方法引入
        // 方式3中的Test12::objGet相当于方式2中的test12 -> test12.objGet()
        TestService testService3 = Test12::objGet;
        System.out.println(testService3.get(new Test12())); //nbgeigei
    }

    public String objGet() {
        return "nbgeigei";
    }
}

案例:

package com.yppah.myLambda.p7;

import java.util.function.Function;

/**
 * @Author: haifei
 * @Date: 2022/10/27 16:56
 */
public class Test13 {

    public static void main(String[] args) {
        //需求: 利用JAVA内置的Function函数接口求字符串长度

        // 方式1:lambda
        Function<String, Integer> function = str->str.length();
        System.out.println(function.apply("123456")); //6

        // 方式2:方法引用
        Function<String, Integer> function2 = String::length;
        System.out.println(function2.apply("654321")); //6
    }
}


方法引入详见置顶链接

posted @ 2022-10-27 14:26  yub4by  阅读(19)  评论(0编辑  收藏  举报