Java基础篇--Lambda表达式

目录

简介

基础语法

Lambda表达式的重要特征 

使用Lambda表达式的优缺点

案例

案例1 无参无返回

案例2 有参有返回值

案例3 final类型参数

Java8内置的函数式接口

Function接口

Consumer接口

Predicate接口

Supplier接口


简介

Lambda表达式(也称闭包)是Java 8中引入的一种新特性,被誉为是该版本最强大的新特性之一,它允许我们将函数作为参数传递给方法,或者将代码视为数据。Lambda表达式可以简化函数式接口的使用,使得代码更加简洁和灵活。

函数式接口是指只包含一个抽象方法的接口。使用Lambda表达式,我们可以将函数作为参数传递给这些接口的方法,从而避免了繁琐的匿名内部类的编写。

基础语法

Lambda表达式的基本语法如下:

(parameters) -> expression

或者

(parameters) -> { statements; }

其中:

  • 参数是函数式接口的参数列表,可以是零个或多个;parameters是函数的参数列表;
  • 箭头(->)将参数列表与表达式或代码块分开
  • expression是Lambda表达式的主体,可以是一个表达式、一个语句块或者一个复杂的代码块;
  • statements是函数体中的多个语句块。

Lambda表达式的重要特征 

  1. 可选类型声明:在Lambda表达式中,不需要声明参数类型,编译器可以统一识别参数值。
  2. 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  3. 可选的大括号:如果主体仅包含一个语句,则不需要使用大括号。
  4. 可选的返回关键字:如果主体只有一个表达式返回值,则编译器会自动返回值,此时大括号需要指定明表达式返回了一个数值。

Lambda表达式的底层实现是以匿名内部类的形式实现的。通过使用Lambda表达式,可以将函数作为参数传递给其他方法,使代码更加简洁和灵活。这有助于提高代码的可读性和可维护性。

使用Lambda表达式的优缺点

优点:

  1. 简洁性:Lambda表达式可以更简洁地定义匿名函数,减少了冗余的代码和样板代码。
  2. 可读性:Lambda表达式可以使代码更易读、理解和维护,特别是对于简单的操作,可以直接在代码中清晰地表达意图。
  3. 函数式编程支持:Lambda表达式为Java引入了函数式编程的能力,使得函数可以作为一等公民,可以将函数作为参数传递、返回函数作为结果,以及使用函数式接口进行操作和组合。
  4. 并行处理:Lambda表达式与集合操作(如Stream API)结合使用,可以方便地实现并行处理,提高程序的运行效率。

缺点:

  1. 学习曲线:对于不熟悉函数式编程概念的开发者来说,学习并理解Lambda表达式的语法和使用方法可能需要一段时间。
  2. 可读性的挑战:虽然Lambda表达式可以使代码更简洁,但在复杂的业务逻辑或大型项目中,过度使用Lambda表达式可能会导致代码难以阅读和理解。
  3. 性能影响:Lambda表达式在某些情况下可能会引入额外的性能开销,尤其是在循环操作中使用Lambda表达式可能导致较高的执行时间。
  4. 使用局限性比较强:Lambda表达式只能适用于接口只有一个抽象方法时使用,不宜调试。

案例

案例1 无参无返回

public class Main {
    public static void main(String[] args) {
        // 使用Lambda表达式定义一个无参无返回值的匿名函数
        Runnable runnable = () -> {
            System.out.println("Hello, Lambda!");
        };

        // 在线程中使用Lambda表达式执行匿名函数
        Thread thread = new Thread(runnable);
        thread.start();
    }
}

案例2 有参有返回值

public class Main {
    public static void main(String[] args) {
        // 使用Lambda表达式定义一个有参有返回值的匿名函数
        Calculator calculator = (int a, int b) -> {
            return a + b;
        };

        // 调用Lambda表达式计算结果
        int result = calculator.calculate(10, 5);
        System.out.println(result); // 输出:15
    }

    // 函数式接口Calculator
    interface Calculator {
        int calculate(int a, int b);
    }
}

案例3 final类型参数

public class Main {
    public static void main(String[] args) {
        // 使用Lambda表达式时,可以不显式声明参数类型,并且可以引用外部的final变量
        final String prefix = "Hello, ";
        Greeting greeting = (name) -> {
            return prefix + name;
        };

        String message = greeting.greet("John");
        System.out.println(message); // 输出:Hello, John
    }

    // 函数式接口Greeting
    interface Greeting {
        String greet(String name);
    }
}

Java8内置的函数式接口

Java8提供了一个java.util.function包,包含了很多函数式接口,下面是其中的四个基本函数式接口:

Java 8 在 java.util.function 包下定义了很多标准函数式接口,主要分为以下几类:

接口 参数 返回值 类别
Consumer T void 消费型接口
Supplier None T 供给型接口
Function T R 函数型接口
Predicate T boolean 断言型接口

Function接口

Function:一个参数,返回一个结果。用于转换一个值到另一个值。

下面是代码案例,演示了使用Function接口的例子:

import java.util.function.Function;

public class Main {
    public static void main(String[] args) {
        // 使用Function接口将字符串转换为整数
        Function stringToInteger = (str) -> Integer.parseInt(str);
        int number = stringToInteger.apply("123");
        System.out.println(number); // 输出:123

        // 使用Function接口将整数加倍,并返回结果的字符串形式
        Function doubleToString = (num) -> String.valueOf(num * 2);
        String result = doubleToString.apply(5);
        System.out.println(result); // 输出:10
    }
}

在上面的代码中,我们首先定义了一个Function接口stringToInteger,用于将字符串转换为整数。然后,我们调用apply()方法传入一个字符串参数,它会执行Lambda表达式并返回转换后的整数。

接着,我们定义了另一个Function接口doubleToString,用于将整数加倍,并将结果转换为字符串。同样地,我们调用apply()方法传入一个整数参数,执行Lambda表达式并返回结果的字符串形式。

Consumer接口

Consumer:一个参数,没有返回值。用于消费一个值或对象。

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

public class Main {
    public static void main(String[] args) {
        // 使用Consumer接口打印字符串列表中的每个元素
        List fruits = Arrays.asList("Apple", "Banana", "Orange");
        Consumer printConsumer = (fruit) -> System.out.println(fruit);
        fruits.forEach(printConsumer);

        // 使用Consumer接口修改字符串列表中的每个元素为大写形式
        List animals = Arrays.asList("cat", "dog", "elephant");
        Consumer uppercaseConsumer = (animal) -> {
            String uppercaseAnimal = animal.toUpperCase();
            System.out.println(uppercaseAnimal);
        };
        animals.forEach(uppercaseConsumer);
    }
}

在以上代码中,我们首先定义了一个Consumer接口printConsumer,用于打印字符串列表中的每个元素。我们使用forEach()方法遍历字符串列表,并在每次迭代时调用accept()方法执行Lambda表达式输出字符串。

接着,我们定义了另一个Consumer接口uppercaseConsumer,用于将字符串列表中的每个元素转换为大写形式并输出。我们在Lambda表达式中执行字符串的大写转换并输出大写结果。

Predicate接口

Predicate:一个参数,返回一个布尔值。用于判断一个条件是否满足。

以下是一个使用Predicate接口的代码示例: 

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class Main {
    public static void main(String[] args) {
        // 创建一个整数列表
        List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // 使用Predicate接口过滤偶数
        Predicate evenPredicate = (number) -> number % 2 == 0;
        List evenNumbers = filterList(numbers, evenPredicate);
        System.out.println("偶数: " + evenNumbers);

        // 使用Predicate接口过滤大于5的数字
        Predicate greaterThanFivePredicate = (number) -> number > 5;
        List greaterThanFiveNumbers = filterList(numbers, greaterThanFivePredicate);
        System.out.println("大于5的数字: " + greaterThanFiveNumbers);
    }

    private static List filterList(List list, Predicate predicate) {
        List result = new ArrayList<>();
        for (Integer number : list) {
            if (predicate.test(number)) {
                result.add(number);
            }
        }
        return result;
    }
}

在上面的代码中,我们首先创建了一个整数列表numbers,包含一组整数。然后,我们定义了两个不同的Predicate接口实例:

  1. evenPredicate用于判断一个数是否为偶数。
  2. greaterThanFivePredicate用于判断一个数是否大于5。

接下来,我们编写了一个名为filterList()的辅助方法,该方法接受一个整数列表和一个Predicate接口作为参数,并返回满足Predicate条件的所有元素所组成的列表。在main()方法中,我们分别使用evenPredicate和greaterThanFivePredicate来过滤numbers列表。然后,将过滤后的结果打印输出。

Supplier接口

Supplier:无参,返回一个结果。用于提供一个值或对象。

以下是一个使用Supplier接口的Java代码示例:

import java.util.Random;
import java.util.function.Supplier;

public class Main {

    public static void main(String[] args) {
        // 使用Supplier接口创建实例
        Supplier randomValueProvider = () -> {
            Random random = new Random();
            int randomInt = random.nextInt(100);
            System.out.println("生成随机数:" + randomInt);
            return randomInt;
        };

        int randomValue1 = randomValueProvider.get();
        System.out.println("第一次获取的随机数:" + randomValue1);

        int randomValue2 = randomValueProvider.get();
        System.out.println("第二次获取的随机数:" + randomValue2);
    }
}

这些函数式接口可以简化代码,并更方便地进行函数式编程。除了上述四个基本接口外,还有其他常用的函数式接口,如BiFunction、UnaryOperator、BinaryOperator等。

你可能感兴趣的:(Java基础篇,java,开发语言)