从初学者到专家:Java的Lambda表达式完整指南

这篇具有很好参考价值的文章主要介绍了从初学者到专家:Java的Lambda表达式完整指南。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

从初学者到专家:Java的Lambda表达式完整指南,Java入门指南,开发语言,java

从初学者到专家:Java的Lambda表达式完整指南,Java入门指南,开发语言,java

一.Lambda的概念

概念:Lambda表达式是Java 8引入的一项重要功能,它允许我们以更简洁和灵活的方式编写代码。可以把Lambda表达式看作是一种更方便的匿名函数,可以像数据一样传递和使用。

使用Lambda表达式可以让我们写出更短、更易读的代码。它可以替代传统的匿名类,使代码更加简洁。Lambda表达式还支持函数式编程,这意味着我们可以将函数作为参数传递给其他方法,使得代码更加灵活和可扩展。

1.1 Lambda表达式的语法

基本语法: (parameters) -> expression (parameters) ->{ statements; }
Lambda表达式由三部分组成:
  1. paramaters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明也可不声明而由JVM隐含的推断。另外当只有一个推断类型时可以省略掉圆括号。
  2. ->:可理解为被用于的意思
  3. 方法体:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不反回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不反回。

根据上面的语法,理解下面的代码:

  1. 对于只有单个表达式的Lambda表达式: 
import java.util.Arrays;
import java.util.List;
public class LambdaExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // Lambda表达式作为参数传递给forEach方法
        numbers.forEach(number -> System.out.print(number+" "));
    }
}

运行截图如下:

从初学者到专家:Java的Lambda表达式完整指南,Java入门指南,开发语言,java

这个示例首先创建了一个整数列表 numbers。然后,通过调用 forEach 方法并传递一个 Lambda 表达式作为参数,对列表中的每个元素执行操作。

2.对于包含多个语句的Lambda表达式:

import java.util.Arrays;
import java.util.List;
public class LambdaExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // Lambda表达式使用多个语句块
        numbers.forEach(number -> {
            int doubled = number * 2;
            System.out.println(number + " doubled: " + doubled);
        });
    }
}

运行截图:

从初学者到专家:Java的Lambda表达式完整指南,Java入门指南,开发语言,java

Lambda 表达式使用了一个语句块,首先计算每个数字的两倍值,并打印原始数字和计算结果。


1.2 函数式接口

要了解 Lambda 表达式 , 首先需要了解什么是函数式接口,函数式接口定义:一个接口有且只有一个抽象方法 。
注意:
  1. 如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口
  2.  如果我们在某个接口上声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接口的定义来要求该接口,这样如果有两个抽象方法,程序编译就会报错的。所以,从某种意义上来说,只要你保证你的接口中只有一个抽象方法,你可以不加这个注解。加上就会自动进行检测的。

举个简单的例子:假设我是一位厨师,需要有一位助手来帮我。你给助手提供了一个简单的任务:切洋葱。你告诉助手只需要进行切洋葱的操作,其他的工作你会负责。 

在这个例子中,我们可以将这个任务看作是一个接口,而助手则是接口的实现者。这个接口定义了一个方法,即切洋葱的操作。

代码案例:



// 定义一个函数式接口
@FunctionalInterface
interface Task {
//注意只能有一个方法
    void perform();
}

public class LambdaExample {
    public static void main(String[] args) {
        // 创建一个助手对象,使用Lambda表达式实现任务
        Task assistant = () -> System.out.println("助手正在切洋葱...");

        // 调用厨师的方法,传递助手对象执行任务
        cookMeal(assistant);
    }

    public static void cookMeal(Task task) {
        // 准备食材
        System.out.println("准备食材...");

        // 执行任务
        task.perform();

        // 煮菜
        System.out.println("开始烹饪...");
    }
}

运行截图:

从初学者到专家:Java的Lambda表达式完整指南,Java入门指南,开发语言,java


如果我在接口再定义一个方法,则会报错。
从初学者到专家:Java的Lambda表达式完整指南,Java入门指南,开发语言,java

但是有另外一种情况可以:

 在Java 8之前,接口中只能包含抽象方法,也就是没有具体的实现。但是,Java 8引入了默认方法的概念,允许在接口中定义具有默认实现的方法。默认方法使用default关键字进行修饰。

由于接口中的默认方法拥有具体的实现,所以你可以直接在接口中调用它们。在实现该接口的类中,可以选择是否覆盖默认方法,如果没有覆盖,默认方法会被继承并直接使用。

现在我在接口定义一个washVegetables()的默认方法。

package demo1;

// 定义一个函数式接口
@FunctionalInterface
interface Task {
    void perform();

    default void washVegetables() {
        System.out.println("助理2,帮我洗菜即可");
    }
}

public class Chef {
    public static void main(String[] args) {
        // 创建一个助手对象,使用Lambda表达式实现任务
        Task assistant1 = () -> {
            System.out.println("助手1正在切洋葱...");
            Task assistant2 = new Task() {
                @Override
                public void perform() {
                    washVegetables();
                }
            };
            assistant2.perform();
        };

        // 调用厨师的方法,传递助手对象执行任务
        cookMeal(assistant1);
    }

    public static void cookMeal(Task task) {
        // 准备食材
        prepareIngredients();

        // 执行任务
        task.perform();

        // 煮菜
        startCooking();
    }

    public static void prepareIngredients() {
        System.out.println("准备食材...");
    }

    public static void startCooking() {
        System.out.println("开始烹饪...");
    }
}

我们将助理1的任务修改为先切洋葱,然后在切洋葱完成后创建一个新的助理2对象,该对象通过实现Task接口并重写perform方法来调用washVegetables默认方法。然后,我们调用助理2的perform方法来执行洗菜操作。


二. Lambda表达式的基本使用

2.1函数接口的六种情况

首先,我们实现准备好几个接口:
//无返回值无参数
@FunctionalInterface
interface NoParameterNoReturn {
void test();
}
//无返回值一个参数
@FunctionalInterface
interface OneParameterNoReturn {
void test(int a);
}
//无返回值多个参数
@FunctionalInterface
interface MoreParameterNoReturn {
void test(int a,int b);
}
//有返回值无参数
@FunctionalInterface
interface NoParameterReturn {
int test();
}
//有返回值一个参数
@FunctionalInterface
interface OneParameterReturn {
int test(int a);
}
//有返回值多参数
@FunctionalInterface
interface MoreParameterReturn {
int test(int a,int b);
}
语法精简:
1. 参数类型可以省略,如果需要省略,每个参数的类型都要省略。
2. 参数的小括号里面只有一个参数,那么小括号可以省略
3. 如果方法体当中只有一句代码,那么大括号可以省略
4. 如果方法体中只有一条语句,且是return语句,那么大括号可以省略,且去掉return关键字。
1.无返回值无参数的函数式接口
@FunctionalInterface
interface NoParameterNoReturn {
    void test();
}

public class TestDemo {
    public static void main(String[] args) {
        // 无参数无返回值的函数式接口
        NoParameterNoReturn noParameterNoReturn = () -> {
            System.out.println("无参数无返回值");
        };
        noParameterNoReturn.test();
    }
     
}

运行截图:

从初学者到专家:Java的Lambda表达式完整指南,Java入门指南,开发语言,java


 2.一个参数无返回值的函数式接口

@FunctionalInterface
interface OneParameterNoReturn {
    void test(int a);
}
public class TestDemo {
    public static void main(String[] args) {
           OneParameterNoReturn oneParameterNoReturn = (int a) -> {
            System.out.println("一个参数无返回值:" + a);
        };
        oneParameterNoReturn.test(10);
     
}

运行截图:

从初学者到专家:Java的Lambda表达式完整指南,Java入门指南,开发语言,java


3.多个参数无返回值的函数式接口

@FunctionalInterface
interface MoreParameterNoReturn {
    void test(int a, int b);
}
public class TestDemo {
    public static void main(String[] args) {
           // 多个参数无返回值的函数式接口
        MoreParameterNoReturn moreParameterNoReturn = (int a, int b) -> {
            System.out.println("多个参数无返回值:" + a + " " + b);
        };
        moreParameterNoReturn.test(20, 30);
     
}

运行截图:

从初学者到专家:Java的Lambda表达式完整指南,Java入门指南,开发语言,java


 4.有返回值无参数的函数式接口

@FunctionalInterface
interface NoParameterReturn {
    int test();
}
public class TestDemo {
    public static void main(String[] args) {
          NoParameterReturn noParameterReturn = () -> {
            System.out.println("有返回值无参数!");
            return 40;
        };
        int ret = noParameterReturn.test();
        System.out.println(ret);
     
}

运行截图:

从初学者到专家:Java的Lambda表达式完整指南,Java入门指南,开发语言,java


5.有返回值一个参数的函数式接口 

@FunctionalInterface
interface OneParameterReturn {
    int test(int a);
}
public class TestDemo {
    public static void main(String[] args) {
         OneParameterReturn oneParameterReturn = (int a) -> {
            System.out.println("有返回值有一个参数!");
            return a;
        };
       int ret = oneParameterReturn.test(50);
        System.out.println(ret);
     
}

运行截图:

从初学者到专家:Java的Lambda表达式完整指南,Java入门指南,开发语言,java


6.有返回值多个参数的函数式接口 

@FunctionalInterface
interface MoreParameterReturn {
    int test(int a, int b);
}
public class TestDemo {
    public static void main(String[] args) {
         MoreParameterReturn moreParameterReturn = (int a, int b) -> {
            System.out.println("有返回值多个参数!");
            return a + b;
        };
        int ret = moreParameterReturn.test(60, 70);
        System.out.println(ret);
     
}

运行截图:

从初学者到专家:Java的Lambda表达式完整指南,Java入门指南,开发语言,java

 2.2匿名内部类变量捕获

 Lambda 表达式中存在变量捕获 ,了解了变量捕获之后,我们才能更好的理解 Lambda 表达式的作用域 。 Java 当中的匿名类中,会存在变量捕获。

 什么是匿名内部类?

匿名内部类就是没有名字的内部类 。我们这里只是为了说明变量捕获,所以,匿名内部类只要会使用就好,那么下面我们来,简单的看看匿名内部类的使用就好了。

代码案例一

interface MyFunction {
    void printValue();
}

public class Example {
    public static void main(String[] args) {
        int x = 10; // 外部作用域的变量

        MyFunction myFunction = new MyFunction() {
            @Override
            public void printValue() {
                // 引用外部作用域的变量x
                System.out.println("x: " + x);
            }
        };

        x = 20; // 修改外部作用域的变量x

        myFunction.printValue(); // 输出捕获的变量x,结果为20
    }
}

我们定义了一个函数式接口MyFunction,其中包含了一个抽象方法printValue()。然后,我们创建了一个匿名内部类实现了该接口,并在实现中引用了外部作用域中的变量x,并打印出其值。 


代码案例二 

interface Shape {
    void draw();
}

public class Example {
    public static void main(String[] args) {
        final int x = 10; // 外部作用域的变量

        Shape shape = new Shape() {
            @Override
            public void draw() {
                System.out.println("Drawing a shape with x = " + x);
            }
        };

        shape.draw(); // 使用匿名内部类重写的draw()方法进行绘制
    }
}

我们定义了一个Shape接口,其中包含了一个抽象方法draw()。然后,我们使用匿名内部类实现了该接口,并在实现中引用了外部作用域中的变量x。在draw()方法中,我们打印出了变量x的值。

 2.3Lambda的变量捕获

Lambda表达式可以捕获外部作用域的变量,这使得Lambda表达式可以访问和操作外部作用域中的变量。捕获的变量在Lambda表达式中被视为"有效final",即虽然没有显式声明为final,但它们在Lambda表达式中不能被修改。
 

代码案例:

@FunctionalInterface
interface NoParameterNoReturn {
    void test();
}

public class TestDemo {
    @FunctionalInterface
    interface NoParameterNoReturn {
        void test();
    }
    public static void main(String[] args) {
        int a = 10;
        NoParameterNoReturn noParameterNoReturn = ()->{
       
            System.out.println("捕获变量:"+a);
        };
        noParameterNoReturn.test();
    }

}

运行截图:

从初学者到专家:Java的Lambda表达式完整指南,Java入门指南,开发语言,java

现在我要修改变量a =99

从初学者到专家:Java的Lambda表达式完整指南,Java入门指南,开发语言,java


三.Lambda在集合当中的使用

为了能够让 Lambda Java 的集合类集更好的一起使用,集合当中,也新增了部分接口,以便与 Lambda 表达式对接。
以下是对应接口的常用方法及其使用:
从初学者到专家:Java的Lambda表达式完整指南,Java入门指南,开发语言,java

 3.1Collection接口

forEach()方法

使用 forEach() 方法可以方便地遍历集合中的元素,并对每个元素执行自定义操作,从而简化了对集合的处理过程。

List<String> fruits = Arrays.asList("Apple", "Banana", "Orange");

fruits.forEach(fruit -> System.out.println("I like " + fruit));

// 输出结果:
// I like Apple
// I like Banana
// I like Orange

removeIf() 方法

removeIf(Predicate<? super E> filter):使用Lambda表达式来移除集合中满足特定条件的元素。Predicate接口的Lambda表达式用于定义过滤条件。
List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));

numbers.removeIf(n -> n % 2 == 0); // 移除所有偶数

// 输出结果:[1, 3, 5]
System.out.println(numbers);

spliterator() 方法

返回一个可用于并行迭代集合的Spliterator对象。Spliterator接口的forEachRemaining()方法可以与Lambda表达式一起使用,对集合中的每个元素执行特定操作。

List<String> fruits = Arrays.asList("Apple", "Banana", "Orange");

Spliterator<String> spliterator = fruits.spliterator();
spliterator.forEachRemaining(fruit -> System.out.println(fruit));

// 输出结果:
// Apple
// Banana
// Orange

stream()方法

返回一个顺序流,用于对集合中的元素进行顺序操作。可以与forEach()方法结合使用,对集合中的每个元素执行特定操作。

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

names.stream()
     .forEach(name -> System.out.println("Hello, " + name));

// 输出结果:
// Hello, Alice
// Hello, Bob
// Hello, Charlie

parallelStream() 方法

 返回一个并行流,用于对集合中的元素进行并行操作。可以与forEach()方法结合使用,对集合中的每个元素执行特定操作。
 

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

names.parallelStream()
     .forEach(name -> System.out.println("Hello, " + name));

// 输出结果:
// Hello, Alice
// Hello, Bob
// Hello, Charlie

 3.2List接口

replaceAll()方法

使用Lambda表达式替换列表中的所有元素。

List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));

numbers.replaceAll(n -> n * 2); // 将列表中的每个元素乘以2

// 输出结果:[2, 4, 6, 8, 10]
System.out.println(numbers);

sort()方法

使用Lambda表达式对列表进行排序。Comparator接口的Lambda表达式用于定义排序逻辑。

List<String> names = new ArrayList<>(Arrays.asList("Alice", "Bob", "Charlie"));

names.sort((name1, name2) -> name1.compareToIgnoreCase(name2)); // 根据名称的字母顺序排序,忽略大小写

// 输出结果:[Alice, Bob, Charlie]
System.out.println(names);

3.3Map接口

forEach()方法

使用Lambda表达式对Map中的每个键值对执行特定的操作。BiConsumer接口的Lambda表达式用于定义操作逻辑,接受键和值作为参数。

Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 90);
scores.put("Bob", 80);
scores.put("Charlie", 95);

scores.forEach((name, score) -> System.out.println(name + ": " + score));

// 输出结果:
// Alice: 90
// Bob: 80
// Charlie: 95

replaceAll()方法

使用Lambda表达式替换Map中的所有值。

Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 90);
scores.put("Bob", 80);
scores.put("Charlie", 95);

scores.replaceAll((name, score) -> score + 5); // 将每个分数加上5

System.out.println(scores);

// 输出结果:
// {Alice=95, Bob=85, Charlie=100}

putIfAbsent()方法

使用Lambda表达式在Map中插入键值对,仅当键不存在时才插入。Lambda表达式用于定义要插入的值,接受键作为参数。

Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 90);
scores.put("Bob", 80);

scores.putIfAbsent("Charlie", 95); // 插入键值对"Charlie=95"

System.out.println(scores);

// 输出结果:
// {Alice=90, Bob=80, Charlie=95}

remove()方法

使用Lambda表达式根据键和值从Map中移除指定的键值对。Lambda表达式用于定义要移除的值,接受键和当前值作为参数。

Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 90);
scores.put("Bob", 80);
scores.put("Charlie", 95);

scores.remove("Alice", 90); // 移除键值对"Alice=90"

System.out.println(scores);

// 输出结果:
// {Bob=80, Charlie=95}

replace()方法

使用Lambda表达式替换Map中指定键的值。Lambda表达式用于定义要替换的值,接受键和当前值作为参数。

Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 90);
scores.put("Bob", 80);
scores.put("Charlie", 95);

scores.replace("Alice", 100); // 将键"Alice"的值替换为100

System.out.println(scores);

// 输出结果:
// {Alice=100, Bob=80, Charlie=95}

四.总结 

Lambda 表达式的优点很明显,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读。
优点:
  • 代码简洁,开发迅速
  • 方便函数式编程
  • 非常容易进行并行计算
  • Java 引入 Lambda,改善了集合操作
缺点:
  • 代码可读性变差
  • 在非并行计算中,很多计算未必有传统的 for 性能要高
  • 不容易进行调试

      

从初学者到专家:Java的Lambda表达式完整指南,Java入门指南,开发语言,java文章来源地址https://www.toymoban.com/news/detail-843330.html

到了这里,关于从初学者到专家:Java的Lambda表达式完整指南的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java初学者也可以实现的图书系统小练习

           大家好呀,我是小戴🙌🙌🙌        最近大家不是快期末了嘛,有没有泡图书馆呀?今天的学习内容跟图书馆有关,没错,就是图书管理系统,但是目前所学知识水平有限,这是一个很简单的图书系统小练习。不要急,我们的 目的是在于如何使用已知学过的知识进

    2023年04月09日
    浏览(50)
  • JAVA-MAVEN初学者教程(配置、pom.xml、依赖管理等)

    Java的包管理工具有Maven、Gradle等,其中Maven是一款服务于Java平台的自动化构建工具,把整个过程抽象成一个项目对象模型(Project Object Model,POM),它不仅可以用作包管理,还有许多的 插件 ,可以支持整个项目 的开发、打包、测试及部署 等一系列行为。Gradle是一个基于Apa

    2024年02月09日
    浏览(56)
  • Mac安装配置Visual Studio Code(vscode)以及Java环境详细教程(初学者必看)

    原本博主今天想继续给大家出Java接下来的教程,但是就在昨天我在配置vscode的时候遇到了一些问题,Windows系统的小伙伴配置起来肯定很方便,但是在Mac的小伙伴却显得十分无奈,所以我想给大家出一篇Mac的Visual Studio Code配置以及Java环境搭建教程! 博客主页:Jovy.的博客_CSDN博客-领

    2024年02月01日
    浏览(89)
  • 进阶JAVA篇- Lambda 表达式与 Lambda 表达式的省略规则

    目录         1.0 什么是 Lambda 表达式?         1.1 既然跟匿名内部类相关,先来回顾匿名内部类。          1.2 Lambda 表达式与匿名内部类之间的关系。         1.3 函数式接口         1.4 在具体代码中来操作一下         2.0 Lambda 表达式省略规则          Lambda 表达

    2024年02月08日
    浏览(58)
  • Java- Lambda表达式

    目录 一、Lambda简介 二、Lambda使用前提 三、Lambda语法 1.操作符 a.\\\"-\\\"  b.\\\"::\\\" 2.格式  a.无参数 b.有参数 四、Lambda演化过程 五、Lambda实现排序 Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)

    2024年02月03日
    浏览(78)
  • Lambda表达式(JAVA)

    注:如果没有学过 匿名内部类 和 接口 不推荐往下看。 (parameters) - expression 或 (parameters) -{ statements; } parameters:表示参数列表; -:可理解为“被用于”的意思; expression:表示一条语句; statements:表示多条语句。 Lambda可以理解为:Lambda就是匿名内部类的简化。 lambda表达式

    2024年02月08日
    浏览(55)
  • Java Lambda表达式

    1.1 函数式编程思想概括 在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿数据做操作” 面向对象思想强调“必须通过对象的形式来做事情” 函数式思想则尽量忽略面

    2024年02月07日
    浏览(63)
  • Java Lambda 表达式

    💗wei_shuo的个人主页 💫wei_shuo的学习社区 🌐Hello World ! Java Lambda 表达式是 Java 8 引入的一种函数式编程特性,它是一种轻量级的匿名函数,允许我们将函数作为方法的参数进行传递。Lambda 表达式可以理解为是一种简洁的方式来表示可传递的代码块,它可以替代传统的匿名内

    2024年02月08日
    浏览(58)
  • java lambda表达式详解

    我们知道,在Java中,接口是不能实例化的,但是接口对象可以指向它的实现类对象。如果接口连实现对象都没有呢?那还可以使用匿名类的方式,如下: 复制 但是,使用匿名内部的方式,代码量其实并不是非常简洁,而为了使代码更加的简洁,Java引进了 Lambda 表达式的写法,

    2024年02月03日
    浏览(51)
  • Java学习——lambda表达式

    什么是Lambda表达式? 可以将Lambda表达式理解为一个匿名函数; Lambda表达式允许将一个函数作为另外一个函数的参数; 我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码作为实参),也可以理解为函数式编程, 将一个函数作为参数进行传递 。 为什么要引入Lambda表

    2024年02月04日
    浏览(68)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包