详解Java之lambda

详解Java之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表达式内部修改外部变量时。 

Read more

Java重入锁(ReentrantLock)全面解析:从入门到源码深度剖析

Java重入锁(ReentrantLock)全面解析:从入门到源码深度剖析

文章目录 * 引言 * 第一部分:重入锁基础概念 * 1.1 什么是重入锁? * 1.2 为什么需要重入锁? * 1.3 ReentrantLock的基本用法 * 第二部分:ReentrantLock的核心特性 * 2.1 可重入性 * 2.2 公平锁与非公平锁 * 2.2.1 概念解析 * 2.2.2 为什么默认非公平锁? * 2.2.3 源码层面的差异 * 2.3 可中断锁 * 2.4 限时等待锁 * 2.5 条件变量(Condition) * 第三部分:ReentrantLock与synchronized的全面对比 * 3.1 异同点总结 * 3.2

By Ne0inhk
Java中的char、String、StringBuilder与StringBuffer 深度详解

Java中的char、String、StringBuilder与StringBuffer 深度详解

文章目录 * 第一章:一切的基础——char原始类型 * 1.1 定义与本质 * 1.2 字符编码的演变:从char到byte * 1.3 char的初始化与赋值 * 1.4 char的运算 * 第二章:不可变的字符串——String类 * 2.1 类的定义与不可变性 * 2.2 不可变性的优势 * 2.3 创建String对象的两种方式 * 2.4 操作的真相:总是生成新对象 * 2.5 字符串拼接的陷阱与优化 * 第三章:可变的字符序列——StringBuilder与StringBuffer * 3.1 AbstractStringBuilder:共同的祖先 * 3.2 StringBuilder:非线程安全的“快枪手” * 3.3

By Ne0inhk
Flutter 三方库 js_wrapping 的鸿蒙化适配指南 - 实现 Dart 与 JavaScript 的无缝对象包装、支持强类型回调与属性映射

Flutter 三方库 js_wrapping 的鸿蒙化适配指南 - 实现 Dart 与 JavaScript 的无缝对象包装、支持强类型回调与属性映射

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 js_wrapping 的鸿蒙化适配指南 - 实现 Dart 与 JavaScript 的无缝对象包装、支持强类型回调与属性映射 前言 在进行 Flutter for OpenHarmony 的 Web 混合开发时,频繁地在 Dart 层与底层 JavaScript 环境进行数据交互是不可避免的。虽然官方提供了基本的 dart:js,但在处理复杂的 JS 对象和回调时,代码往往会变得杂乱无章。js_wrapping 提供了一个更优雅的、类型安全的包装层。本文将指导大家如何在鸿蒙端利用该库提升 JS 互操作的开发体验。 一、原理解析 / 概念介绍 1.1 基础原理

By Ne0inhk
【人工智能离散数学基础】——深入详解组合数学:理解组合问题在某些AI算法中的应用

【人工智能离散数学基础】——深入详解组合数学:理解组合问题在某些AI算法中的应用

深入详解组合数学:理解组合问题在某些AI算法中的应用         组合数学(Combinatorics)是数学的一个分支,研究离散对象的组合、排列及其性质。组合数学在计算机科学和人工智能(AI)领域中有广泛的应用,特别是在优化问题、搜索算法、概率模型和图论等方面。本文将深入探讨组合数学的基础知识,重点解析其在AI算法中的应用,并通过示例代码帮助读者更好地理解这些概念。 目录 1. 引言 2. 组合数学基础 * 基本概念与原则 * 排列与组合 * 高级主题 3. 组合数学在AI中的应用 * 优化问题 * 搜索与决策算法 * 概率与统计模型 * 图论与网络分析 4. 具体应用案例 * 特征选择 * 模型选择 * 超参数调优 * 约束满足问题 5. 示例代码 * 组合生成与枚举 * 特征选择示例 * 动态规划与组合优化 6. 总结与展望 7. 参考资料 1. 引言 组合数学作为研究离散结构的数学分支,提供了处理和分析组合问题的工具和方法。在人工智能领

By Ne0inhk