Java 8 Lambda 表达式

论坛 期权论坛 脚本     
匿名技术用户   2021-1-4 19:52   25   0

一、Java8新特性

Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 表达式是一种匿名函数,简单地说,它是没有声明的方法,也即没有访问修饰符、返回值声明和名字。

Lambda 允许把函数作为一个方法的参数(即把lambda表达式作为匿名函数,传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑。

语法:

lambda 表达式的语法格式如下:

(parameters) -> expression 或 (parameters) ->{ statements; }

语法:( ) -> { }() : 括号就是接口方法的括号,接口方法如果有参数,也需要写参数。只有一个参数时,括号可以省略。-> : 分割左右部分的,没啥好讲的。{} : 要实现的方法体。只有一行代码时,可以不加括号,可以不写return。

不过看到这里我相信有些小伙伴已经许意识到了,如果接口中有多个方法时,那么按照上面的逻辑lambda表达式恐怕没办法表示了。的确是这样,并非任何接口都支持lambda表达式。

而适用于lambda表达式的接口称之为函数型接口。说白了,函数型接口就是只有一个抽象方法的接口。

二、Lambda 表达式实例

// 1. 不需要参数,返回值为 5  
() -> 5  
  
// 2. 接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x  
  
// 3. 接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y  
  
// 4. 接收2个int型整数,返回他们的和  
(int x, int y) -> x + y  
  
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
(String s) -> System.out.print(s)


public class Java8Tester {
    public static void main(String args[]){
        Java8Tester tester = new Java8Tester();

        // 类型声明
        MathOperation addition = (int a, int b) -> a + b;

        // 不用类型声明
        MathOperation subtraction = (a, b) -> a - b;

        // 大括号中的返回语句
        MathOperation multiplication = (int a, int b) -> { return a * b; };

        // 没有大括号及返回语句
        MathOperation division = (int a, int b) -> a / b;

        System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
        System.out.println("1 + 3 = " + addition.operation(1,3));

        System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
        System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
        System.out.println("10 / 5 = " + tester.operate(10, 5, division));

        // 不用括号
        GreetingService greetService1 = message ->
                System.out.println("Hello " + message);

        // 用括号
        GreetingService greetService2 = (message) ->
                System.out.println("Hello " + message);

        greetService1.sayMessage("Runoob");
        greetService2.sayMessage("Google");
    }

    //只包含一个抽象方法的接口,称为函数式接口。以下都是函数式接口
    interface MathOperation {
        int operation(int a, int b);
    }

    interface GreetingService {
        void sayMessage(String message);
    }
    //方法
    private int operate(int a, int b, MathOperation mathOperation){
        return mathOperation.operation(a, b);
    }
}

使用 Lambda 表达式需要注意以下两点:

  • Lambda 表达式主要用来定义行内执行的方法类型接口,例如,一个简单方法接口。在上面例子中,我们使用各种类型的Lambda表达式来定义MathOperation接口的方法。然后我们定义了sayMessage的执行。
  • Lambda 表达式免去了使用匿名方法的麻烦,并且给予Java简单但是强大的函数化的编程能力。

三、什么是函数式接口

Lambda是建立在函数式接口的基础上的。

记住!

(1)只包含一个抽象方法的接口,称为函数式接口。

(2)你可以通过 Lambda 表达式来创建该接口的对象。

(3)我们可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检测它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。

在实际开发者两个比较常见的函数式接口:Runnable接口,Comparator接口

先举例Runnable接口相关



public class LambdaDemo3 {

        public static void main(String[] args) {

            // 1.1使用匿名内部类
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("Hello world !");
                }
            }).start();

            // 1.2使用 lambda 获得Runnable接口对象
            new Thread(() -> System.out.println("Hello world !")).start();

//=============================================================================

            // 2.1使用匿名内部类
            Runnable race1 = new Runnable() {
                @Override
                public void run() {
                    System.out.println("Hello world !");
                }
            };

            // 2.2使用 lambda直接获得接口对象
            Runnable race2 = () -> System.out.println("Hello world !");

            // 直接调用 run 方法(没开新线程哦!)
            race1.run();
            race2.run();
        }
}

再举一个例子:使用Lambda对数组排序

import java.util.Arrays;
import java.util.Comparator;

public class LambdaDemo4 {

        public static void main(String[] args) {
            String[] players = {"zhansgan", "lisi", "wangwu", "zhaoliu",  "wangmazi"};

            // 1.1 使用匿名内部类根据 surname 排序 players
            Arrays.sort(players, new Comparator<String>() {
                @Override
                public int compare(String s1, String s2) {
                    return (s1.compareTo(s2));
                }
            });

            // 1.2 使用 lambda 排序,根据 surname
            Arrays.sort(players, (String s1, String s2) ->  s1.compareTo(s2));

//================================================================================================

            // 2.1 使用匿名内部类根据 name lenght 排序 players
            Arrays.sort(players, new Comparator<String>() {
                @Override
                public int compare(String s1, String s2) {
                    return (s1.length() - s2.length());
                }
            });

            // 2.2使用Lambda,根据name length
            Arrays.sort(players, (String s1, String s2) -> (s1.length() - s2.length()));

//==================================================================================================

            // 3.1 使用匿名内部类排序 players, 根据最后一个字母
            Arrays.sort(players, new Comparator<String>() {
                @Override
                public int compare(String s1, String s2) {
                    return (s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1));
                }
            });

            // 3.2 使用Lambda,根据最后一个字母
            Arrays.sort(players, (String s1, String s2) -> (s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1)));
        }
}

通过上面例子我们再来思考为什么Lambda表达式需要函数式接口?其实很简单目的就是为来保证唯一。

你的Runnable接口只要一个抽象方法,那么我用() -> System.out.println("Hello world !"),就只能代表run方法,如果你下面还有一个抽象方法,那我使用Lambda表达式,那鬼才知道要调用哪个抽象方法呢。

四、方法引用

1、基本介绍

首先注意:方法引用,不是方法调用!

函数式接口的实例可以通过 lambda 表达式、 方法引用、构造方法引用来创建。方法引用是 lambda 表达式的语法糖,任何用方法引用的地方都可由lambda表达式替换,但是并不是所有的lambda表达式都可以用方法引用来替换。

public class TestArray {
    
    public static void main(String[] args) {
         List<String> list = Arrays.asList("xuxiaoxiao", "xudada", "xuzhongzhong");
           list.forEach(value -> System.out.println(value));
    }
}

使用方法引用的方式,和上面的输出是一样的,方法引用使用的是双冒号(::)

list.forEach(System.out::println);

分类:

类别 使用形式
静态方法引用 类名 :: 静态方法名
实例方法引用 对象名(引用名) :: 实例方法名
类方法引用 类名 :: 实例方法名
构造方法引用 类名 :: new

public class Apple {
    private String name;
    private String color;
    private double weight;

    int num = 5;

    public Apple(String name, String color, double weight) {
        this.name = name;
        this.color = color;
        this.weight = weight;
    }
//构造方法
    public Apple() {
        System.out.println(num);
        System.out.println("this is contruction");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    @Override
    public String toString() {
        return "Apple{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", weight=" + weight +
                '}';
    }

//静态方法
    public static int compareByWeight(Apple a1, Apple a2) {
        double diff = a1.getWeight() - a2.getWeight();
        return new Double(diff).intValue();
    }
//实例方法
    public int compareByWeight2(Apple a1, Apple a2) {
        double diff = a1.getWeight() - a2.getWeight();
        return new Double(diff).intValue();
    }
//类方法(参数传类)
    public int compareByWeight3(Apple other) {
        //this是当前类的apple,other是传进来的
        double diff = this.getWeight() - other.getWeight();
        return new Double(diff).intValue();
    }

}

import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;

public class LambdaDemo2 {

    public LambdaDemo2(){
        System.out.println("当前构造方法");
    }
    public static void main(String[] args) {
        //静态方法引用
        Apple apple1 = new Apple("红富士", "Red", 280);
        Apple apple2 = new Apple("冯心", "Yello", 470);
        Apple apple3 = new Apple("大牛", "Red", 320);
        Apple apple4 = new Apple("小小", "Green", 300);
        List<Apple> appleList = Arrays.asList(apple1, apple2, apple3, apple4);
        //lambda 表达式形式
//            appleList.sort((Apple a1, Apple a2) -> {
//                return new Double(a1.getWeight() - a2.getWeight()).intValue();
//            });

        //静态方法引用形式(可以看出引用方法比上面的更加简单
        appleList.sort(Apple::compareByWeight);

//        appleList.forEach(apple -> System.out.println(apple));

        //实例方法引用
        Apple comparator = new Apple();
        appleList.sort(comparator::compareByWeight2);
//        appleList.forEach(apple -> System.out.println(apple));

        //类方法引用
        appleList.sort(Apple::compareByWeight3);
//        appleList.forEach(apple -> System.out.println(apple));

        //构造方法引用
        Supplier<Apple> apple = Apple::new;

        //当前类需调用get
        Supplier<LambdaDemo2> dangqian = LambdaDemo2::new;
        dangqian.get();
    }

}


分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP