首页 > 编程语言 >详解Java之lambda

详解Java之lambda

时间:2024-10-20 10:17:37浏览次数:8  
标签:Java System 接口 详解 println lambda out 表达式 Lambda

目录

lambda

引入

语法

函数式接口

lambda表达式的使用

语法精简:

代码示例:

变量捕获

局部变量捕获

成员变量捕获

lambda在集合中的使用

lambda的优缺点


lambda
引入

Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。Lambda 表达式可以看作是一个匿名函数。

语法

基本语法: (parameters) -> expression或(parameters) ->{ statements; }

Lambda表达式由三部分组成:

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

函数式接口

要了解Lambda表达式,首先需要了解什么是函数式接口。

函数式接口定义:一个接口有且只有一个抽象方法。 

注意:

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

代码示例1:

@FunctionalInterface
interface NoParameterNoReturn {
    void test();
}

代码示例2:

@FunctionalInterface
interface NoParameterNoReturn {
    void test();
    default void test2(){
        System.out.println("JDK1.8新特性,default默认方法可以有具体的实现");
    }
}
lambda表达式的使用
Lambda 表达式本质是一个匿名函数,函数的方法是:返回值方法名参数列表方法体。在, Lambda 表达式中我们只需要关心:参数列表方法体。
语法精简:

1. 参数类型可以省略,如果需要省略,每个参数的类型都要省略。
2. 参数的小括号里面只有一个参数,那么小括号可以省略
3. 如果方法体当中只有一句代码,那么大括号可以省略
4. 如果方法体中只有一条语句,要么是输出语句,其次是return语句,那么大括号可以省略,且去掉return关键字。 

代码示例:
//无返回值无参数
@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);
}


public class Test {
    public static void main(String[] args) {
        /*NoParameterNoReturn noParameterNoReturn = ()->System.out.println("test.....");
        noParameterNoReturn.test();*/

        /*OneParameterNoReturn oneParameterNoReturn = (x) -> {
            System.out.println(x);
        };*/
        /*OneParameterNoReturn oneParameterNoReturn = x -> System.out.println(x);
        oneParameterNoReturn.test(10);*/

        /*MoreParameterNoReturn moreParameterNoReturn = (int x,int y) -> {
            System.out.println(x+y);
        };*/

        /*OneParameterReturn oneParameterReturn = a -> a;
        System.out.println(oneParameterReturn.test(10));*/
/*
        NoParameterReturn noParameterReturn = ()->{return 10;};
*/
       /* NoParameterReturn noParameterReturn = ()-> 10;
        System.out.println(noParameterReturn.test());*/


        MoreParameterNoReturn moreParameterNoReturn = (x,y) ->  System.out.println(x+y);

        moreParameterNoReturn.test(10,20);

    }
}
变量捕获

在Java中,Lambda表达式允许以更简洁的方式实现接口中的方法。Lambda表达式可以捕获其所在上下文中有效的final或effectively final(实际上final,即在Lambda表达式内部没有被修改)的局部变量和成员变量。这种捕获机制使得Lambda表达式能够访问和使用这些变量,而无需显式地将它们作为参数传递给Lambda表达式。

局部变量捕获

对于局部变量,Lambda表达式只能捕获那些被声明为final或者实际上未被修改的变量(effectively final)。这意味着即使变量没有被显式地声明为final,但如果你在Lambda表达式之外没有修改这个变量的值,那么这个变量也可以被Lambda表达式捕获。

public class LambdaDemo {  
    public static void main(String[] args) {  
        final int number = 10; // 显式声明为final  
        int anotherNumber = 20; // 实际上final,因为之后没有被修改  
  
        // 使用Lambda表达式  
        Runnable r = () -> System.out.println(number); // 可以捕获number  
        // Runnable r = () -> System.out.println(anotherNumber); // 也可以捕获anotherNumber  
  
        // 如果尝试修改anotherNumber,则上面的Lambda表达式将无法编译  
        // anotherNumber = 30;  
  
        r.run();  
    }  
}
成员变量捕获

与局部变量不同,Lambda表达式可以直接访问所在类的成员变量,无论这些成员变量是否被声明为final。这是因为成员变量是类的属性,它们的生命周期与类的实例相同,而Lambda表达式只是类的实例的一个方法或者构造器中的一部分。 

public class LambdaDemo {  
    private int classVariable = 42;  
  
    public void display() {  
        Runnable r = () -> System.out.println(classVariable); // 直接访问成员变量  
        r.run();  
    }  
  
    public static void main(String[] args) {  
        new LambdaDemo().display();  
    }  
}

总结

1.Lambda表达式内部不能修改捕获的局部变量(除非这些变量是数组或集合的元素,并且2.Lambda表达式通过引用访问这些元素)。
3.Lambda表达式可以捕获并访问类的成员变量和静态变量,无需任何限制。
4.Java 8及以上版本支持Lambda表达式。

lambda在集合中的使用
为了能够让 Lambda 和 Java 的集合类集更好的一起使用,集合当中,也新增了部分接口,以便与 Lambda 表达式对接。
对应的接口新增的方法
CollectionremoveIf(),spliterator(),stream(),parallelStream(),forEach()
ListreplaceAll(),sort()
MapgetOrDefault(),forEach(),replaceAll(),putIfAbsent(),remove(),replace(),merge()

代码示例:

public class Test2 {
    public static void main(String[] args) {
        Map<String,Integer> map = new HashMap<>();
        map.put("hello",13);
        map.put("abc",3);
        map.put("zhangsan",31);
        /*map.forEach(new BiConsumer<String, Integer>() {
            @Override
            public void accept(String s, Integer integer) {
                System.out.println("key: "+s +" val: "+integer);
            }
        });*/
        map.forEach((s, integer) ->  System.out.println("key: "+s +" val: "+integer));
    }
    public static void main1(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("hello");
        list.add("abc");
        list.add("zhangsan");
        /*list.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });*/

        list.forEach(s -> System.out.println(s));

       /* list.sort(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });*/
        list.sort((o1, o2) -> o1.compareTo(o2));
        System.out.println("====");
        list.forEach(s -> System.out.println(s));

    }
}
lambda的优缺点

优点

1.代码简洁性:Lambda表达式可以使得代码更加简洁易读,尤其是当实现简单的接口时。相比传统的匿名内部类,Lambda表达式在语法上更加简洁。
2.增强功能性接口的使用:Lambda表达式常与功能性接口(Functional Interface,即只包含一个抽象方法的接口)一起使用,使得这些接口的实现变得更加容易和直观。
3.易于并行计算:Java 8的Streams API与Lambda表达式相结合,使得数据集的并行处理变得简单而高效。开发者可以轻松地将顺序操作转换为并行操作,从而提高程序的执行效率。
4.促进函数式编程风格:Lambda表达式和Streams API等特性促进了Java中函数式编程风格的应用,使得Java不再仅仅是面向对象的编程语言,也可以用于实现更加灵活的函数式编程范式。
5.提升API的设计:Lambda表达式使得API的设计更加灵活和强大。开发者可以设计出更加通用和灵活的接口,以适应不同的使用场景。

缺点:

1.学习曲线:对于习惯于传统Java编程范式的开发者来说,Lambda表达式和Streams API等新特性可能需要一定的时间来学习和适应。
2.调试难度:由于Lambda表达式在语法上的简洁性,有时候可能会使得调试变得更加困难。尤其是在复杂的Lambda表达式中,追踪错误来源可能会比较棘手。
3.性能开销:虽然Lambda表达式在大多数情况下不会对性能产生显著影响,但在某些极端情况下(如大量使用Lambda表达式和Streams API进行密集计算),可能会引入一定的性能开销。这是因为Lambda表达式和Streams API的底层实现可能需要更多的内存和CPU资源。
4.可读性和可维护性:虽然Lambda表达式可以使代码更加简洁,但在某些情况下,过度使用或滥用Lambda表达式可能会降低代码的可读性和可维护性。例如,过于复杂的Lambda表达式可能会使得其他开发者难以理解其逻辑。
5.限制了变量的使用:Lambda表达式内部只能访问标记为final或effectively final的局部变量。这一限制可能会在某些情况下造成不便,尤其是当需要在Lambda表达式内部修改外部变量时。 

标签:Java,System,接口,详解,println,lambda,out,表达式,Lambda
From: https://blog.csdn.net/wmh_1234567/article/details/141280972

相关文章

  • 树状数组——原理详解
    前言这两天在网上学树状数组,但是发现网上关于树状数组的解释大都对初学者不太友善,原理讲解部分并不是很容易理解,所以写了一篇树状数组,顺便帮自己巩固一下。一、什么是树状数组1.概念:简单来说,这是一种数据结构。顾名思义,它通过树的结构来对数组进行高效操作,一般用于求数组前缀......
  • 测开必备-java基础-for循环语句的用法
    什么是for循环?for循环的基本结构什么是for循环?for循环是一种编程中的控制结构,它允许你重复执行一段代码固定的次数。当你需要执行一系列重复的任务时,for循环就非常有用。for循环的基本结构在Java中,for循环的基本结构如下:for (初始化表达式; 循环条件; 步进表达式) {  ......
  • java计算机毕业设计基于的旅游景区指南系统的设计与实现(开题+程序+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容一、研究背景随着社会经济的不断发展,旅游业蓬勃兴起,人们的旅游需求日益增长 12。如今旅游景区数量众多且分布广泛,游客在面对海量的旅游目的地时,往往难以抉择......
  • Java毕设项目案例实战II基于Spring Boot的药店管理系统的设计与实现(开发文档+数据库+
    目录一、前言二、技术介绍三、系统实现四、论文参考五、核心代码六、源码获取全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末一、前言随着医疗行业的快速发展和人们对健康需求......
  • Java之反射机制详解
    一、基本概念Java反射(Reflection)是一种允许程序在运行时动态地检查和操作类、接口、字段、方法等内部信息的机制。通过反射,程序可以在不知道对象类型的情况下创建对象、调用方法和访问字段,甚至访问私有成员。反射机制为Java程序提供了极大的灵活性和扩展性,是Java语言中一个......
  • 第二部分 Java基本语法
    第二部分Java基本语法一个main方法头文件包含如下:2.1标识符Java所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。关于Java标识符,有以下几点需要注意:所有的标识符都应该以字母(A-Z或者a-z),美元符($)、或者下划线(_)开始首字符之后可以是字母(A-Z或......
  • Java设计模式——适配器模式
    适配器模式(AdapterPattern)是一种结构型设计模式,它用于将一个类的接口转换成客户端希望的另一个接口,使得原本由于接口不兼容而无法一起工作的类可以协同工作。适配器模式的主要目的是兼容性和重用性,特别是在使用一些已有的类,而它们的接口又不符合要求时。适配器模式的核心思想......
  • JavaScript中的this指向
    1.函数在调用时,JavaScript会默认给this绑定一个值;2.this的绑定和定义的位置(编写的位置)没有关系;3.this的绑定和调用方式以及调用的位置有关系;4.this是在运行时被绑定的;this的绑定规则规则一:默认绑定在函数独立调用时使用默认绑定,可以理解为函数没有被绑定到某个对象上常见......
  • Java的重载和主要内存区
    JAVA的重载​在Java中,重载(Overloading)是指在同一个类中可以定义多个同名的方法,但它们的参数列表必须不同。重载可以通过改变参数的数量、类型或者顺序来实现。重载提高了代码的可读性和灵活性。JAVA重载要满足的条件:在同一个类下:java的重载必须在同一个类之下方法名相同......
  • 【Java】Java面向对象与方法
    1.基本方法1.1.基本定义在Java中,方法即为函数,Java中的方法定义遵循下面的通用格式修饰符返回值方法名(形参列表){方法体}对于基本方法的定义,遵循下面的结构publicstatic返回类型方法名(形参列表){方法体}是否需要返回类型和形参列表需要看该......