Java8 新特性 Lambda表达式

简介

Java 8 引入的 Lambda 表达式是函数式编程在 Java 中的一个重要特性。Lambda 表达式允许你以更简洁的方式实现只有一个抽象方法的接口(即函数式接口)的匿名内部类。这使得 Java 代码更加简洁、易读和易维护。

函数式编程的概念

函数式编程(Functional Programming, FP)是一种编程范式,它强调将计算过程看作是函数之间的转换而不是状态的改变。函数式编程的核心思想是将计算机程序视为一系列数学函数的组合,通过函数来描述运算过程,并尽量不改变外界状态,从而避免多线程共享变量的问题。函数式编程的主要特性包括:

  1. 函数是一等公民:在函数式编程中,函数可以被当作参数传递给其他函数,也可以作为其他函数的返回值。
  2. 纯函数:纯函数是函数式编程中的核心概念,它指的是函数的输出仅由输入决定,不会对外部状态产生影响,也不会产生副作用。
  3. 不可变性:函数式编程通常使用不可变数据结构,这意味着数据一旦创建就不能被修改。
  4. 高阶函数:高阶函数是可以接受其他函数作为参数或返回一个函数的函数。
  5. 延迟计算:函数式编程支持延迟计算,即只有在需要的时候才进行计算,这可以避免不必要的计算。
  6. 递归(Recursion):使用递归而不是循环来实现重复的操作。
  7. 声明式编程(Declarative Programming):关注“做什么”而不是“怎么做”,与命令式编程(Imperative Programming)相对。
  8. 模式匹配(Pattern Matching):用于数据结构的解析和处理,如在 Haskell 或 Scala 中的模式匹配。
  9. 惰性评估(Lazy Evaluation):计算只有在需要时才执行,可以提高性能和内存效率。
  10. 并发编程(Concurrency):由于纯函数和不可变性的特性,函数式编程语言通常更容易处理并发和并行计算。

函数式编程的优点

函数式编程具有多个显著的优点,这些优点使得它在现代软件开发中越来越受到重视:

  1. 代码简洁性和可读性:函数式编程通过简洁的函数组合来表达复杂的逻辑,使得代码更加简洁易读。
  2. 模块化开发:函数式编程鼓励将程序拆分成多个小的函数,每个函数负责完成一个特定的任务,这有助于实现模块化开发,提高代码的可维护性。
  3. 可重用性:函数式编程中的函数可以被多次调用,提高了代码的可重用性,减少了代码重复。
  4. 易于测试和调试:由于函数式编程中的函数通常具有较小的依赖性和较少的副作用,因此更容易进行单元测试和调试。
  5. 并发安全性:由于函数式编程中的纯函数不会修改外部状态,因此可以更容易地实现并发编程,减少并发错误的发生。
  6. 支持数学和逻辑推导:函数式编程与数学和逻辑紧密相关,支持使用数学和逻辑推导来验证程序的正确性。

函数式接口

函数式接口是只有一个抽象方法的接口(可以有多个默认方法和静态方法)。@FunctionalInterface 注解是一个标记注解,用于表明接口是函数式接口,但这不是强制性的。如果接口不符合函数式接口的定义(即包含多个抽象方法),但使用了 @FunctionalInterface 注解,编译器会报错。

Lambda 表达式的优点和缺点

优点:

  • 代码简洁,开发迅速
  • 方便函数式编程
  • 容易进行并行计算
  • Java 引入 Lambda,改善了集合操作

缺点:

  • 代码可读性变差
  • 在非并行计算中,很多计算未必有传统 for 循环性能高
  • 不容易进行调试

Lambda 表达式与接口实现的比较

  1. 传统接口实现方式

    • 实现接口的类

      public interface MyFunctionalInterface {
          void doSomething();
      }
      
      public class MyFunctionalInterfaceImpl implements MyFunctionalInterface {
          @Override
          public void doSomething() {
              System.out.println("Doing something!");
          }
      }
      
    • 匿名内部类

      MyFunctionalInterface myFunc = new MyFunctionalInterface() {
          @Override
          public void doSomething() {
              System.out.println("Doing something!");
          }
      };
      
  2. Lambda 表达式

    Lambda 表达式的引入使得上述两种实现方式都变得更加简洁:

    MyFunctionalInterface myFunc = () -> System.out.println("Doing something!");
    
  3. 测试

@Test
void stream() {
    MyFunctionalInterfaceImpl myFunc = new MyFunctionalInterfaceImpl();
    myFunc.doSomething();
    MyFunctionalInterface myFunc1 = () -> System.out.println("Doing something2!");
    myFunc1.doSomething();
    MyFunctionalInterface myFunc2 = new MyFunctionalInterface() {
        @Override
        public void doSomething() {
            System.out.println("Doing something3!");
        }
    };
    myFunc2.doSomething();
}

1、Lambda 表达式的语法

1.1 Lambda 表达式提供了一种简洁的方式来表示匿名函数。其基本语法如下:

(参数列表) -> 表达式

 (parameters) -> expression

或 (参数列表) -> { Lambda 体 }

(parameters) -> { statements; }
  • 无参数

    Runnable runnable = () -> System.out.println("Hello, World!");
    
  • 一个参数

     Function<String, Integer> stringLength = s -> s.length();
    
  • 多个参数

     BinaryOperator<Integer> add = (a, b) -> a + b;
    
1.2 Java 7(使用匿名类)和 Java 8(使用 Lambda 表达式)之间参数形式的对比:
Java 7 (匿名类)Java 8 (Lambda 表达式)
new Comparator<String>() { @Override public int compare(String s1, String s2) { return s1.compareTo(s2); } }(s1, s2) -> s1.compareTo(s2)
new Runnable() { @Override public void run() { System.out.println("Hello, World!"); } }() -> System.out.println("Hello, World!")
new Callable<String>() { @Override public String call() throws Exception { return "Hello, Lambda!"; } }() -> "Hello, Lambda!"
new Function<Integer, Integer>() { @Override public Integer apply(Integer t) { return t * t; } }(t) -> t * t

2、Lambda表达式规则

  1. 参数类型可以省略:如果 Lambda 表达式的参数类型可以从上下文中推断出来,那么可以省略参数类型,例如 (int a)(a) 效果相同。

  2. 单参数的小括号可以省略:如果 Lambda 表达式只有一个参数,那么可以省略这个参数周围的小括号,例如 (a)a 效果相同。

  3. 单行方法体可以省略大括号:如果 Lambda 表达式的方法体只包含一条语句,那么可以省略大括号。

  4. 单行方法体的返回语句可以省略 return 关键字:如果 Lambda 表达式的方法体只有一条返回语句,那么可以省略 return 关键字。

3、示例

  1. 简单的Lambda表达式

    // 使用Lambda表达式打印信息
    Runnable r = () -> System.out.println("Hello, Lambda!");
    r.run();
    
  2. 使用单个参数的Lambda表达式

    // 使用Lambda表达式对集合中的每个元素执行操作
    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    names.forEach(name -> System.out.println(name));
    
  3. 使用多个参数的Lambda表达式

    // 使用Lambda表达式比较两个字符串
    List<String> strings = Arrays.asList("Apple", "Banana", "Cherry");
    Collections.sort(strings, (s1, s2) -> s2.compareTo(s1));
    strings.forEach(System.out::println);
    
  4. Lambda表达式作为方法参数

    // 使用Lambda表达式作为方法的参数
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
    int sum = numbers.stream().reduce(0, (acc, item) -> acc + item);
    System.out.println("Sum: " + sum);
    
  5. Lambda表达式与方法引用

    // 使用方法引用作为Lambda表达式
    numbers.forEach(System.out::println);
    
  6. Lambda表达式与构造器引用

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    class Person {
        private String name;
        private int age;
    }
    
    @Test
    void stream() {
        // 使用Lambda表达式创建对象
        Supplier<Person> personSupplierLambda = () -> new Person();
    
        // 使用构造器引用创建对象
        Supplier<Person> personSupplierRef = Person::new;
    
        // 使用Supplier来创建Person对象
        Person personSupplier1 = personSupplierLambda.get();
        Person personSupplier2 = personSupplierRef.get();
        personSupplier1.setAge(20);
        personSupplier1.setName("Alice");
        personSupplier2.setAge(18);
        personSupplier2.setName("Bob");
        // 如果Person有一个接受名字和年龄的构造器,我们可以这样使用它(假设存在一个合适的函数式接口)
        // 注意:这里需要自定义或找到一个合适的函数式接口,比如BiFunction<String, Integer, Person>
        // 但为了简单起见,我们仅展示概念
         BiFunction<String, Integer, Person> personCreator = Person::new;
         Person personSupplier3 = personCreator.apply("Charlie", 30);
        System.out.println(personSupplier1);
        System.out.println(personSupplier2);
        System.out.println(personSupplier3);
    }
    
  7. Lambda表达式与泛型

    // 使用Lambda表达式转换数据类型
    List<String> stringList = Arrays.asList("1", "2", "3");
    List<Integer> integerList = stringList.stream().map(Integer::parseInt).collect(Collectors.toList());
    integerList.forEach(System.out::println);
    
  8. Lambda表达式与高阶函数

    高阶函数的定义:

    • 接受函数作为参数:如果一个函数可以接受另一个函数作为参数,那么这个函数就是高阶函数。
    • 返回函数作为结果:如果一个函数可以返回另一个函数,那么这个函数也是高阶函数。
    // 使用Lambda表达式作为高阶函数的参数
    List<String> filtered = strings.stream()
        .filter(s -> s.startsWith("A"))
        .collect(Collectors.toList());
    
  9. Lambda表达式与排序

    // 使用Lambda表达式进行复杂排序
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    class Person {
        private String name;
        private int age;
    }
    
    @Test
    void stream() {
        List<Person> people = Arrays.asList(new Person("Alice", 30), new Person("Bob", 25));
        people.sort((p1, p2) -> p1.age - p2.age);
        System.out.println(people);
    }
    

这些示例展示了Lambda表达式在Java 8中的多种用法,包括简单的操作、集合处理、方法引用、泛型以及高阶函数。Lambda表达式使得代码更加简洁和易于理解。

  • 21
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java 8引入了lambda表达式作为一种新的编程语言特性。lambda表达式是一种匿名函数,它可以作为参数传递给方法或存储在变量中。它可以简化代码,使代码更加易读和易维护。lambda表达式的语法非常简洁,可以用来替代匿名内部类。它可以在集合框架中使用,使代码更加简洁和易读。lambda表达式Java 8中最重要的新特性之一,它使Java编程更加现代化和高效。 ### 回答2: Lambda 表达式是 Java 8 中最重要的新增特性之一,它可以让我们以更简洁的方式来编写代码,并且能够更优雅的解决许多问题。 Lambda 表达式本身是一个匿名函数,它可以被当做对象进行传递和处理。它强调的是函数式编程思想,将函数作为一等公民,并支持灵活的函数组合。Lambda 表达式通常由左侧的参数列表、箭头符号和右侧的函数体组成。例如: ``` (x, y) -> x + y ``` 上述代码定义了一个 lambda 表达式,这个表达式接受两个参数 x 和 y,然后返回它们的和。 Lambda 表达式的用途非常广泛,它们通常用于简化代码,比如用于普通的遍历集合和数组: ``` List<String> names = Arrays.asList("alice", "bob", "charlie"); names.forEach(name -> System.out.println(name)); ``` Lambda 表达式还可以用于函数式接口,这是一种只包含一个抽象方法的接口。函数式接口可以被当做 lambda 表达式的类型,这意味着我们可以使用 lambda 表达式来创建这种类型的对象。例如: ``` interface Calculator { int calculate(int a, int b); } Calculator add = (a, b) -> a + b; Calculator sub = (a, b) -> a - b; ``` 上述代码定义了一个接口类型 Calculator,它包含一个抽象方法 calculate,并且使用 lambda 表达式来定义 add 和 sub 两个对象,它们分别代表加法和减法。 Lambda 表达式还支持方法引用,这是一种更简洁的语法形式,它允许我们使用方法名来代替 lambda 表达式的函数体。例如: ``` List<String> names = Arrays.asList("alice", "bob", "charlie"); names.forEach(System.out::println); ``` 上述代码使用了方法引用,它代替了之前的 lambda 表达式。 总之,Java 8 的 Lambda 表达式是一项非常有用的功能,它提供了一种更简单的方式来编写代码,让我们的代码更加简约且易于阅读。同时,它也是一种函数式编程思想的体现,让 Java 开发者能够更好的应用这些思想来解决实际问题。 ### 回答3: Java8的lambda表达式是一个Java编程语言新特性,它可以方便地为函数式接口创建实例。Lambda表达式允许你直接以更加简单和精简的方式来定义内部类,并且能够省略掉那些没有用的代码。 在Java 8中,Lambda表达式通过一个箭头“->”来定义。在箭头左边是参数列表,这些参数可以是任何类型,但是Lambda表达式中只能有一个方法参数。在箭头右边是Lambda表达式的主体,也就是这个Lambda表达式所要执行的代码块。 Lambda表达式还可以访问外部作用域中的变量,这是通过捕获变量的方式来实现的。Lambda表达式在使用外部变量时会将其捕获到Lambda表达式内部,从而形成一个闭包,这使得Lambda表达式能够访问外部的变量。 Lambda表达式的使用能够使得代码更加简洁,能够将代码逻辑更加清晰地表达。在Java8中,Lambda表达式被广泛应用于集合的处理,比如通过对集合进行排序、过滤、映射等操作,能够更加简单地处理数据集合。Lambda表达式还被应用于多线程的编程中,能够使得并发编程更加方便和简单。 总之,Java 8的Lambda表达式是一个很有用的新特性。它能够使得Java代码更加简洁和易于理解,减少了冗余的结构和语法。同时,它也提供了更加灵活的编程方式,使得Java编程能够更加高效和便利。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值