找回密码
 会员注册
查看: 36|回复: 0

JavaLambda表达式

[复制链接]

2万

主题

0

回帖

6万

积分

超级版主

积分
64454
发表于 2024-9-3 17:05:34 | 显示全部楼层 |阅读模式
文章目录一、Lambda表达式1.1相关背景1.2函数式编程1.3匿名内部类和Lambda表达式二、Lambda表达式的使用2.1基本语法2.2使用案例三、变量捕获3.1匿名内部类的变量捕获3.2Lambda表达式的变量捕获四、Lambda表达式在集合中的使用4.1Collection接口4.2List接口4.3Map接口五、Lambda表达式的优缺点一、Lambda表达式1.1相关背景Lambda表达式是Java8引入的一个重要特性,它是函数式编程在Java中的一种体现。在Java之前的版本中,Java主要采用面向对象的编程风格,而Lambda表达式的引入使得Java具备了函数式编程的能力。1.2函数式编程函数式编程是一种编程范式,它将计算过程视为函数应用的连续组合。函数式编程强调使用纯函数(PureFunction),避免使用可变状态和副作用,倡导将计算过程抽象为函数,便于代码的理解、测试和并行化。Lambda表达式允许将函数作为方法的参数,或者将代码块作为数据进行传递。它的引入主要解决了以下几个问题:匿名内部类的冗余代码:在Java之前的版本中,为了实现函数的传递,常常需要使用匿名内部类来定义一个函数接口的实现。这导致代码冗长、可读性较差。Lambda表达式的引入简化了匿名内部类的语法,让代码更加简洁明了。函数式编程的支持:函数式编程强调将函数作为第一类对象进行传递和操作。Lambda表达式提供了一种便捷的语法形式,使得函数可以作为参数传递给方法,或者作为返回值返回。并行编程的支持:函数式编程中的纯函数天然具备无副作用的特性,这使得在并行编程中更容易实现可靠的多线程和并行处理。Lambda表达式的引入使得Java在并行编程方面具备了更好的支持。1.3匿名内部类和Lambda表达式匿名内部类和Lambda表达式都是在Java中用于实现函数式编程的机制,它们可以用来传递行为(函数)作为参数或返回值。匿名内部类:匿名内部类是在Java早期引入的一种机制,用于创建一个没有命名的、实现了某个接口或抽象类的类的实例。通过匿名内部类,可以在使用某个接口或抽象类的地方,直接定义一个实现该接口或抽象类的实例。匿名内部类通常通过创建一个子类来实现,并且在实例化的同时定义实现的方法。例如,以下是使用匿名内部类实现Runnable接口的例子:Threadthread=newThread(newRunnable(){publicvoidrun(){System.out.println("Hellofromanonymousinnerclass");}});thread.start();123456Lambda表达式:Lambda表达式是Java8中引入的一种更简洁、更直观的方式来表示函数式接口(只有一个抽象方法的接口)的实例。Lambda表达式提供了一种更简洁的语法,使得可以以更紧凑的方式传递行为。使用Lambda表达式,可以直接定义一个函数式接口的实例,而无需创建匿名内部类。以下是使用Lambda表达式实现相同功能的例子:Threadthread=newThread(()->{System.out.println("HellofromLambdaexpression");});thread.start();1234Lambda表达式使用箭头->将参数和函数体分隔开,参数可以有零个或多个,函数体可以是一个表达式或一段代码块。Lambda表达式的引入让Java代码更具表达力和简洁性,提高了代码的可读性和可维护性。总结来说,匿名内部类和Lambda表达式都可以用来实现函数式编程,传递行为作为参数或返回值。匿名内部类是一种更早引入的机制,Lambda表达式是Java8中引入的更简洁、更直观的方式。根据具体的场景和需求,可以选择使用匿名内部类或Lambda表达式来实现相应的功能。二、Lambda表达式的使用2.1基本语法Lambda表达式的基本语法如下:(parameters)->expression1或(parameters)->{statements;}1其中,参数可以是任意合法的Java参数列表,可以为空或包含一个或多个参数。箭头(->)将参数与Lambda主体分隔开来。Lambda主体可以是一个表达式,也可以是一个代码块。如果主体是一个表达式,它将直接返回该表达式的结果。如果主体是一个代码块,它将按照常规的Java语法执行,并且您可能需要使用return语句来返回值。下面是一些Lambda表达式的示例:无参数的Lambda表达式:()->System.out.println("Hello,Lambda!");1带有参数的Lambda表达式:(x,y)->System.out.println(x+y);1带有多行代码的Lambda表达式:(x,y)->{intsum=x+y;System.out.println("Sum:"+sum);returnsum;}12345Lambda表达式可以与函数式接口一起使用,函数式接口是只包含一个抽象方法的接口。在Lambda表达式中,根据上下文的要求,可以自动匹配函数式接口的抽象方法,并创建接口的实例。2.2使用案例//无返回值无参数@FunctionalInterface//函数式接口,检查作用interfaceNoParameterNoReturn{voidtest();}//无返回值一个参数@FunctionalInterfaceinterfaceOneParameterNoReturn{voidtest(inta);}//无返回值多个参数@FunctionalInterfaceinterfaceMoreParameterNoReturn{voidtest(inta,intb);}//有返回值无参数@FunctionalInterfaceinterfaceNoParameterReturn{inttest();}//有返回值一个参数@FunctionalInterfaceinterfaceOneParameterReturn{inttest(inta);}//有返回值多参数@FunctionalInterfaceinterfaceMoreParameterReturn{inttest(inta,intb);}publicclassTest1{publicstaticvoidmain(String[]args){MoreParameterReturnmoreParameterReturn=(x,y)->x+y;intsum=moreParameterReturn.test(1,2);System.out.println(sum);}publicstaticvoidmain6(String[]args){OneParameterReturnoneParameterReturn=(x)->x+1;intret=oneParameterReturn.test(10);System.out.println(ret);}publicstaticvoidmain5(String[]args){//NoParameterReturnnoParameterReturn=()->{return10;};NoParameterReturnnoParameterReturn=()->10;intret=noParameterReturn.test();System.out.println(ret);}publicstaticvoidmain4(String[]args){MoreParameterNoReturnmoreParameterNoReturn=(x,y)->System.out.println(x+y);moreParameterNoReturn.test(10,20);}publicstaticvoidmain3(String[]args){//OneParameterNoReturnoneParameterNoReturn=(x)->System.out.println("x:"+x);OneParameterNoReturnoneParameterNoReturn=x->System.out.println("x:"+x);//OneParameterNoReturnoneParameterNoReturn=System.out::println;oneParameterNoReturn.test(10);}publicstaticvoidmain2(String[]args){//相当于一个匿名内部类实现了一个接口,重写了接口当中的方法NoParameterNoReturnnoParameterNoReturn=()->System.out.println("test()");noParameterNoReturn.test();}publicstaticvoidmain1(String[]args){//匿名内部类NoParameterNoReturnnoParameterNoReturn=newNoParameterNoReturn(){@Overridepublicvoidtest(){System.out.println("test()");}};noParameterNoReturn.test();}}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889上述代码展示了在Java中使用Lambda表达式的各种情况,涵盖了无返回值无参数、无返回值一个参数、无返回值多个参数、有返回值无参数、有返回值一个参数、有返回值多个参数的情况。三、变量捕获3.1匿名内部类的变量捕获在Java中,匿名内部类可以捕获外部变量,即在匿名内部类中引用并访问外部作用域的变量。这种行为称为变量捕获(VariableCapturing)。在匿名内部类中,可以捕获以下类型的变量:实例变量(InstanceVariables):如果匿名内部类位于一个实例方法中,它可以捕获并访问该实例的实例变量。静态变量(StaticVariables):匿名内部类可以捕获并访问包含它的类的静态变量。方法参数(MethodParameters):匿名内部类可以捕获并访问包含它的方法的参数。本地变量(LocalVariables):匿名内部类可以捕获并访问声明为final的本地变量。从Java8开始,final关键字可以省略,但该变量实际上必须是最终的(即不可修改)。当匿名内部类捕获变量时,它们实际上是在生成的字节码中创建了一个对该变量的副本。这意味着即使在外部作用域中的变量发生改变,匿名内部类中捕获的变量仍然保持其最初的值。以下是一个示例,展示了匿名内部类捕获外部变量的用法:publicclassOuterClass{privateintinstanceVariable=10;privatestaticintstaticVariable=20;publicvoidmethod(){finalintlocalVar=30;//或者直接使用Java8+的隐式finalRunnablerunnable=newRunnable(){@Overridepublicvoidrun(){System.out.println("Instancevariable:"+instanceVariable);System.out.println("Staticvariable:"+staticVariable);System.out.println("Localvariable:"+localVar);}};runnable.run();}}12345678910111213141516171819在上面的示例中,method()方法中创建了一个匿名内部类的实例,并在该类的run()方法中访问了外部的实例变量、静态变量和本地变量localVar。这些变量都被匿名内部类捕获并访问。需要注意的是,如果在匿名内部类中捕获非final或非最终的变量,或者在Java8之前的版本中捕获非final的变量,编译器将报错。从Java8开始,可以捕获对final变量的隐式引用,无需显式地将其声明为final。3.2Lambda表达式的变量捕获在Lambda表达式中,同样可以捕获外部作用域的变量。Lambda表达式可以捕获以下类型的变量:实例变量(InstanceVariables):Lambda表达式可以捕获并访问包含它的实例的实例变量。静态变量(StaticVariables):Lambda表达式可以捕获并访问包含它的类的静态变量。方法参数(MethodParameters):Lambda表达式可以捕获并访问包含它的方法的参数。本地变量(LocalVariables):Lambda表达式可以捕获并访问声明为final的本地变量。从Java8开始,final关键字可以省略,但该变量实际上必须是最终的(即不可修改)。与匿名内部类不同,Lambda表达式不会创建对变量的副本,而是直接访问变量本身。这意味着在Lambda表达式中捕获的变量在外部作用域中发生的改变也会在Lambda表达式中反映出来。以下是一个示例,展示了Lambda表达式捕获外部变量的用法:publicclassLambdaVariableCapture{privateintinstanceVariable=10;privatestaticintstaticVariable=20;publicvoidmethod(){intlocalVar=30;//Lambda表达式捕获外部变量Runnablerunnable=()->{System.out.println("Instancevariable:"+instanceVariable);System.out.println("Staticvariable:"+staticVariable);System.out.println("Localvariable:"+localVar);};runnable.run();}}1234567891011121314151617在上面的示例中,method()方法中创建了一个Lambda表达式,捕获了外部的实例变量、静态变量和本地变量localVar。Lambda表达式中直接使用这些变量,无需声明。需要注意的是,与匿名内部类一样,如果在Lambda表达式中捕获非final或非最终的变量,或者在Java8之前的版本中捕获非final的变量,编译器将报错。从Java8开始,可以隐式捕获对final变量的引用,无需显式地将其声明为final。另外,Lambda表达式还有一个特点是它们可以访问外部作用域的变量,但不能修改它们的值。这是因为Lambda表达式中的变量是相当于隐式声明的final变量,一旦捕获,就不允许修改。四、Lambda表达式在集合中的使用为了能够让Lambda和Java的集合类集更好的一起使用,集合当中也新增了部分接口,以便与Lambda表达式对接。4.1Collection接口Lambda表达式在Collection接口中的使用主要涉及对集合进行迭代、筛选和转换等操作。在Java8及以上的版本中,Collection接口增加了一些默认方法,例如forEach()、removeIf()和stream()等,使得使用Lambda表达式更加方便。下面是Lambda表达式在Collection接口中的常见应用示例:迭代集合元素:Listnames=Arrays.asList("Alice","Bob","Charlie");names.forEach(name->System.out.println(name));123筛选集合元素:Listnumbers=Arrays.asList(1,2,3,4,5,6,7,8,9,10);numbers.removeIf(n->n%2==0);123转换集合元素:Listnames=Arrays.asList("Alice","Bob","Charlie");ListnameLengths=names.stream().map(name->name.length()).collect(Collectors.toList());12345获取集合流:Listnumbers=Arrays.asList(1,2,3,4,5);Streamstream=numbers.stream();123使用filter()筛选集合元素:Listnames=Arrays.asList("Alice","Bob","Charlie");ListfilteredNames=names.stream().filter(name->name.startsWith("A")).collect(Collectors.toList());12345以上示例展示了Lambda表达式在Collection接口中的常见应用场景。通过Lambda表达式,我们可以以更简洁、更灵活的方式对集合进行迭代、筛选和转换等操作。4.2List接口Lambda表达式在List接口中的使用主要涉及到对集合元素的遍历、过滤、映射和归约等操作。下面是一些常见的Lambda表达式在List接口中的应用示例:遍历列表元素:Listfruits=Arrays.asList("Apple","Banana","Orange");fruits.forEach(fruit->System.out.println(fruit));123过滤列表元素:Listnumbers=Arrays.asList(1,2,3,4,5);ListevenNumbers=numbers.stream().filter(number->number%2==0).collect(Collectors.toList());12345映射列表元素:Listnames=Arrays.asList("Alice","Bob","Charlie");ListnameLengths=names.stream().map(name->name.length()).collect(Collectors.toList());12345查找列表元素:Listfruits=Arrays.asList("Apple","Banana","Orange");OptionalfoundFruit=fruits.stream().filter(fruit->fruit.startsWith("B")).findFirst();12345排序列表元素:Listnumbers=Arrays.asList(5,2,8,1,6,3,9,4,7,10);ListsortedNumbers=numbers.stream().sorted().collect(Collectors.toList());12345以上示例展示了Lambda表达式在List接口中的一些常见应用场景。通过Lambda表达式和StreamAPI,我们可以以更简洁、更直观的方式对列表进行操作和处理。4.3Map接口Lambda表达式在Map接口中的使用可以通过Java8引入的StreamAPI和Map的相关方法来实现。下面是一些Lambda表达式在Map接口中的常见应用示例:迭代Map的键值对:Mapmap=newHashMap();map.put("Alice",25);map.put("Bob",30);map.put("Charlie",35);map.forEach((key,value)->System.out.println(key+":"+value));123456遍历Map的键或值:Mapmap=newHashMap();map.put("Alice",25);map.put("Bob",30);map.put("Charlie",35);map.keySet().forEach(key->System.out.println(key));map.values().forEach(value->System.out.println(value));1234567使用Stream过滤Map的键值对:Mapmap=newHashMap();map.put("Alice",25);map.put("Bob",30);map.put("Charlie",35);MapfilteredMap=map.entrySet().stream().filter(entry->entry.getValue()>30).collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue));123456789对Map的值进行映射:Mapmap=newHashMap();map.put("Alice",25);map.put("Bob",30);map.put("Charlie",35);MapmappedMap=map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,entry->"Age:"+entry.getValue()));12345678对Map的键或值进行归约操作:Mapmap=newHashMap();map.put("Alice",25);map.put("Bob",30);map.put("Charlie",35);intsumOfValues=map.values().stream().reduce(0,(a,b)->a+b);StringconcatenatedKeys=map.keySet().stream().reduce("",(a,b)->a+b);1234567以上示例展示了Lambda表达式在Map接口中的常见应用场景。通过使用Lambda表达式和StreamAPI,可以以简洁、灵活的方式操作和处理Map的键值对数据。五、Lambda表达式的优缺点Lambda表达式在Java中引入了函数式编程的概念,具有许多优点和一些限制。下面是Lambda表达式的主要优点和缺点:优点:简洁性:Lambda表达式提供了一种更简洁、更紧凑的语法,可以减少冗余的代码和样板代码,使代码更易于理解和维护。代码可读性:Lambda表达式使得代码更加自解释和易读,可以直接将逻辑集中在一起,提高代码的可读性和可维护性。便于并行处理:Lambda表达式与Java8引入的StreamAPI结合使用,可以方便地进行集合的并行处理,充分发挥多核处理器的优势,提高代码的执行效率。避免匿名内部类的繁琐语法:相比于使用匿名内部类,Lambda表达式的语法更为简洁,减少了冗余的代码,提高了编码效率。缺点:只能用于函数式接口:Lambda表达式只能用于函数式接口(只有一个抽象方法的接口),这限制了它的使用范围。如果需要使用非函数式接口,仍然需要使用传统的方式,如匿名内部类。可读性的折衷:尽管Lambda表达式可以提高代码的可读性,但在某些复杂的情况下,Lambda表达式可能变得难以理解和阅读,特别是当表达式变得过于复杂时。变量捕获的限制:Lambda表达式对捕获的变量有一些限制。它们只能引用final或实际上的最终变量,这可能对某些情况下的代码编写和调试带来一些困扰。学习曲线:对于习惯于传统Java编程风格的开发者来说,Lambda表达式是一项新的概念,需要一定的学习和适应过程。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-28 05:57 , Processed in 0.443401 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表