Java 8的变革:函数式编程和Lambda表达式探索

在这里插入图片描述

文章目录

    • 一、函数接口
    • 二、Lambda表达式简介
    • 三、Lambda表达式外部参数
    • 四、Lambda范例
    • 五、Runnable Lambda表达式

一、函数接口

函数接口是一个具有单个抽象方法的接口,接口设计主要是为了支持 Lambda 表达式和方法引用,使得 Java 能更方便地实现函数式编程风格。

特点和用途:

  1. 单一抽象方法: 函数接口只能有一个抽象方法,但可以有多个默认方法(default)或静态方法(static)。
  2. Lambda 表达式: 可以使用函数接口创建 Lambda 表达式,从而简洁地表示匿名函数,例如在集合操作、线程处理等场景中。
  3. 方法引用: 可以通过函数接口的类型来引用一个已存在的方法,使代码更简洁和可读性更高。

Java 8 提供了几个标准的函数接口,接口通常位于 java.util.function 包中。

常见的函数接口:

  • Consumer: 接收一个输入参数并且不返回结果的操作。

    Consumer<String> printConsumer = str -> System.out.println(str);
    printConsumer.accept("Hello World!");
    
  • Supplier: 不接收参数但是返回结果的提供型接口。

    Supplier<Double> randomSupplier = () -> Math.random();
    System.out.println(randomSupplier.get());
    
  • Function: 接收一个输入参数,并返回结果。

    Function<Integer, String> intToString = num -> String.valueOf(num);
    System.out.println(intToString.apply(123));
    
  • Predicate: 接收一个输入参数,并返回一个布尔值结果。

    Predicate<Integer> isEven = num -> num % 2 == 0;
    System.out.println(isEven.test(5)); // false
    
  • UnaryOperator: 继承自 Function<T, T>,表示一元操作符。

    UnaryOperator<Integer> square = num -> num * num;
    System.out.println(square.apply(5)); // 25
    

自定义函数接口:只需确保接口中只有一个抽象方法即可。

@FunctionalInterface
interface MyFunctionalInterface {void myMethod();// 允许有默认方法和静态方法default void anotherMethod() {System.out.println("Default method");}
}// 使用自定义的函数接口
MyFunctionalInterface myFunc = () -> System.out.println("Hello Custom Functional Interface");
myFunc.myMethod();
myFunc.anotherMethod();

二、Lambda表达式简介

Lambda 表达式可以被视为匿名函数的一种声明方式,允许将函数作为方法参数传递,或者在需要函数式接口的地方使用。

基本结构:

// parameters:参数列表,可以为空或非空
// ->:箭头符号,分隔参数列表和Lambda表达式的主体
// expression:单行表达式作为 Lambda 主体
(parameters) -> expression// { statements; }:代码块作为 Lambda 主体,可以包含多条语句和返回语句
(parameters) -> { statements; }

表达式的特点:

  1. 简洁性和可读性: Lambda 表达式使代码更为简洁,尤其是在处理函数式接口时,省去了冗余的语法。
  2. 函数式编程风格: Lambda 表达式支持函数式编程,可以轻松地进行函数传递、方法引用和流式操作等。
  3. 闭包性: Lambda 表达式可以捕获其周围的变量,使得函数式编程中的状态管理更加灵活。

案例:通过 Lambda 表达式为 MathOperation 接口的 operation 方法提供了四种不同的实现:加法、减法、乘法和除法。

  1. 接口的定义:
interface MathOperation {int operation(int a, int b);
}
  1. 使用 Lambda 表达式来实现这个接口,以便传递不同的数学运算逻辑:
public class LambdaDemo {public static void main(String[] args) {// Lambda 表达式实现加法MathOperation addition = (int a, int b) -> a + b;System.out.println("10 + 5 = " + operate(10, 5, addition));// Lambda 表达式实现减法MathOperation subtraction = (a, b) -> a - b;System.out.println("10 - 5 = " + operate(10, 5, subtraction));// Lambda 表达式实现乘法MathOperation multiplication = (int a, int b) -> { return a * b; };System.out.println("10 * 5 = " + operate(10, 5, multiplication));// Lambda 表达式实现除法MathOperation division = (a, b) -> a / b;System.out.println("10 / 5 = " + operate(10, 5, division));}private static int operate(int a, int b, MathOperation mathOperation) {return mathOperation.operation(a, b);}
}

三、Lambda表达式外部参数

Lambda 表达式有自己特定的作用域规则,可以捕获和访问其周围的变量, 可以随意引用外部变量,但如果外部变量是在当前作用域声明的,则一定不可以进行第二次赋值,哪怕是在 lambda 语句之后。

  1. 局部变量:Lambda 表达式可以访问它们所在方法的局部变量,但是这些变量必须是隐式最终或实际上是最终的(final)。这意味着变量一旦赋值后不再改变。Lambda 表达式内部不允许修改这些局部变量的值,否则编译器会报错。

    public class LambdaScopeDemo {public static void main(String[] args) {int num = 10; // 局部变量MathOperation addition = (int a, int b) -> {// num = 5; // 错误!Lambda 表达式不能修改局部变量的值// 这里访问了局部变量 numreturn a + b + num;};System.out.println(addition.operation(5, 3));}
    }
    
  2. 字段:Lambda 表达式可以访问外部类的字段(成员变量),包括实例字段和静态字段。

    public class LambdaScopeDemo {private static int staticNum; // 静态字段private int instanceNum; // 实例字段public void testLambdaScope() {MathOperation addition = (int a, int b) -> {// 访问实例字段和静态字段int result = a + b + instanceNum + staticNum;return result;};System.out.println(addition.operation(5, 3));}
    }
    
  3. 接口的默认方法:Lambda 表达式可以访问接口中定义的默认方法,但不能访问接口中定义的实例字段。

四、Lambda范例

使用Lambda表达式时,常见的场景包括对集合的遍历、排序、过滤以及与函数式接口的结合使用。

常见的Java 8 Lambda表达式示例

  1. 遍历集合
public static void main(String[] args) {List<String> names = new ArrayList<>();names.add("Alice");names.add("Bob");names.add("Charlie");// 使用 Lambda 表达式遍历集合names.forEach(name -> System.out.println(name));}
  1. 使用函数式接口进行计算

参考二、Lambda表达式简介

  1. 使用函数式接口进行条件过滤
public static void main(String[] args) {List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);// 使用 Lambda 表达式过滤偶数System.out.println("偶数:");filter(numbers, n -> n % 2 == 0);// 使用 Lambda 表达式过滤大于 5 的数System.out.println("大于 5 的数:");filter(numbers, n -> n > 5);}private static void filter(List<Integer> numbers, Predicate<Integer> condition) {for (Integer number : numbers) {if (condition.test(number)) {System.out.print(number + " ");}}System.out.println();}
  1. 使用Comparator进行集合排序
public static void main(String[] args) {List<String> names = new ArrayList<>();names.add("Alice");names.add("Bob");names.add("Charlie");// 使用 Lambda 表达式进行排序(根据字符串长度)names.sort((s1, s2) -> s1.length() - s2.length());// 输出排序后的结果names.forEach(name -> System.out.println(name));}
  1. 使用 Runnable 执行代码块

参考五、Runnable Lambda表达式

五、Runnable Lambda表达式

使用 Lambda 表达式来简洁地实现 Runnable 接口的实例化。Runnable 接口是一个函数接口,它只包含一个抽象方法 void run(),用于定义一个可以由线程执行的任务。

  1. 匿名内部类(Java 7 及之前):
Runnable runnable = new Runnable() {@Overridepublic void run() {System.out.println("Running in a separate thread");}
};Thread thread = new Thread(runnable);
thread.start();
  1. Lambda 表达式(Java 8+)
Runnable runnable = () -> {System.out.println("Running in a separate thread");
};Thread thread = new Thread(runnable);
thread.start();
  1. 更简洁的方式:任务非常简单,可以进一步简化,直接将 Lambda 表达式作为参数传递给 Thread 的构造函数:
Thread thread = new Thread(() -> {System.out.println("Running in a separate thread");
});
thread.start();

这种方式避免了显式地声明 Runnable 变量,使代码更加紧凑和易读。

案例:

public static void main(String[] args) {// 使用 Lambda 表达式创建一个新的线程Thread thread = new Thread(() -> {for (int i = 0; i < 5; i++) {System.out.println("线程执行:" + i);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});// 启动线程thread.start();}

莫道君行早,更有早行人

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3248677.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【排序算法】—— 计数排序

一、简介 计数排序&#xff0c;顾名思义就是记录数据出现的次数进行排序&#xff0c;时间复杂度为O(NK)&#xff0c;空间复杂度为O(N)。只能用于整型&#xff0c;对于比较集中重复率比较高数据更为适用。 二、排序原理 比如对接下来这些数进行排序 arr[11] { 8,6,4,1,6,2,9,…

国产化低功耗HDMI转VGA方案,大量出货产品,广泛应用在显示器以及广告机产品

芯片描述&#xff1a; 兼具高性能和低成本效益的优点&#xff0c;是一款可以将高清视频 HDMI1.4 数字信号转换成 VGA 模拟信号输出的芯片。不需要提供外部电源&#xff0c;ICNM7301 就可以在正常模式下使用&#xff1b;ICNM7301 广 泛适用于各种市场系统和显示应用体系&#x…

Bash 学习摘录

文章目录 1、变量和参数的介绍&#xff08;1&#xff09;变量替换$(...) &#xff08;2&#xff09;特殊的变量类型export位置参数shift 2、引用&#xff08;1&#xff09;引用变量&#xff08;2&#xff09;转义 3、条件判断&#xff08;1&#xff09;条件测试结构&#xff08…

vue自定义折叠Tree,自定义折叠树

使用组件 <TreeNode v-for"(node, index) in nodes" :key"index" :node"node" />JSON数据 let nodes[{"id": 2030,"show_id": "MC1813024492270223360","detail_type": 1,"title": &…

Geometric Transformer for Fast and Robust Point Cloud Registration 论文解读

目录 一、导言 二、先导知识 1、超点匹配 2、KPConv 三、相关工作 1、基于对应的方法 2、直接配准方法 3、深度鲁棒估计 四、GeoTransformer模型 1、特征提取 2、超点匹配 几何自注意力模块 特征交叉注意力 计算高斯相关性 对应点采样 3、点匹配 4、局部到全局…

花开半夏,我决意仿一款答题小程序

不是清凉罢挥扇&#xff0c;自缘手倦歇些时。 ——杨万里&#xff08;宋&#xff09; 走过春的绚烂&#xff0c;路过初夏的清凉&#xff0c;我们迎来了炎炎夏日。蛙声阵阵&#xff0c;蝉鸣声声&#xff0c;稻花如白练&#xff0c;荷花别样红。 花开半夏&#xff0c;我决意仿一款…

陕西技术交易大会璀璨起航,卓翼飞思无人智能领域研究成果备受瞩目

智启未来&#xff0c;链动四方。万众瞩目的陕西省技术交易大会于7月17-18日在西安璀璨启航&#xff01;大会聚焦智能感知及其上下游产业链&#xff0c;旨在促进四链深度融合&#xff0c;推动技术创新与产业发展。卓翼智能作为产业链中“智能感知应用端”的杰出企业代表&#xf…

【刷题专项】— 模拟

1、替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 首先找到需要替换的 ? &#xff0c;位置然后遍历26个字母与 ? 的左右两边的是否相同&#xff0c;不同的话就替换最后返回即可代码&#xff1a; public String modifyString(String s) {char[] c…

MySQL运维实战之Clone插件(10.1)使用Clone插件

作者&#xff1a;俊达 clone插件介绍 mysql 8.0.17版本引入了clone插件。使用clone插件可以对本地l或远程的mysql实例进行clone操作。clone插件会拷贝innodb存储引擎表&#xff0c;clone得到的是原数据库的一个一致性的快照&#xff0c;可以使用该快照数据来启动新的实例。cl…

Android View的绘制流程

1.不管是View的添加&#xff0c;还是调用View的刷新方法invalidate()或者requestLayout()&#xff0c;绘制都是从ViewRootImpl的scheduleTraversals()方法开始 void scheduleTraversals() {if (!mTraversalScheduled) {mTraversalScheduled true;mTraversalBarrier mHandler…

【论文速读】| TCSR-SQL:面向表内容感知的自检索文本到SQL方法

本次分享论文&#xff1a;TCSR-SQL: Towards Table Content-aware Text-to-SQL with Self-retrieval 基本信息 原文作者&#xff1a;Wenbo Xu, Liang Yan, Peiyi Han, Haifeng Zhu, Chuanyi Liu, Shaoming Duan, Cuiyun Gao, Yingwei Liang 作者单位&#xff1a;哈尔滨工业大…

Java垃圾收集器选择与优化策略

1.垃圾收集算法有哪些,可以聊一下吗? 如何确定一个对象是垃圾? 要想进行垃圾回收,得先知道什么样的对象是垃圾。 1.1 引用计数法 对于某个对象而言,只要应用程序中持有该对象的引用,就说明该对象不是垃圾。如果一个对象没有任何指针对其引用,它就是垃圾。 弊端:如果…

【网络工具】Charles 介绍及环境配置

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/iAmAo &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会整理一些工作或学习中用到的工具介绍给大家~ &#x1f4d8;Charles 系列其它文章&#xff1a;【网络…

JavaScript基础 第四弹 学习笔记

函数 1、为什么需要函数&#xff1f;可以实现代码复用&#xff0c;提高开发效率。 函数的定义 &#xff1a;函数function&#xff0c;是被设计为执行特定任务的代码块。 函数可以把具有相同或相似逻辑的代码‘包裹’起来&#xff0c;通过函数调用执行这些被“包裹”的代码逻…

万界星空科技电线电缆MES系统实现线缆全流程追溯

MES系统通过高度集成的数据平台&#xff0c;对电线电缆的生产全过程进行实时监控与记录&#xff0c;从原材料入库开始&#xff0c;到生产过程中的各个关键控制点&#xff0c;再到成品出库&#xff0c;每一步操作都被详细记录并可追溯。这种全流程追溯能力主要体现在以下几个方面…

java基础之变量,类型的转换,跟着哔站尚硅谷自学笔记。

变量 变量的介绍以及使用 1.变量的数据类型&#xff1a;基本数据类型&#xff1a;4类8种整数&#xff1a;byte short int long 浮点数&#xff1a;float double字符型&#xff1a;char布尔型&#xff1a;boolean引用数据类型&#xff1a;类 数组 接口 枚举 注解2.概述&#xf…

云南合续-马来西亚水环境项目考察单位

2024年恰逢中马建交50周年&#xff0c;中华环保联合会为进一步加强双方生态产业合作与交流&#xff0c;拟定于9月23日-29日组团赴马来西亚开展水环境项目考察&#xff0c;同期举办“2024中马水务合作论坛”&#xff0c;引领国内先进环保技术、装备、产能“走出去”。

hung 之 Android llkd

目录 1. llkd 简介 2. 原理 2.1 内核活锁 2.2 检测机制 2.3 为什么 persistent stack signature 检测机制不执行 ABA 检查&#xff1f; 2.4 为什么 kill 进程后&#xff0c;进程还存在就能判定发生了内核 live-lock&#xff1f; 3. 代码 3.1 内核 live-lock 检查 3.2 …

verilog刷题笔记

1、选择器实现方式 &#xff08;1&#xff09;case语句&#xff0c;注意default &#xff08;2&#xff09;if-else语言&#xff0c;注意else&#xff0c;有优先级 &#xff08;3&#xff09;三元运算符 &#xff1f; &#xff1a; 2、阻塞赋值/非阻塞赋值都是过程性赋值&a…

使用崖山YMP 迁移 Oracle/MySQL 至YashanDB 23.2 验证测试

前言 首届YashanDB「迁移体验官」开放后&#xff0c;陆续收到「体验官」们的投稿&#xff0c;小崖在此把优秀的投稿文章分享给大家~今天分享的用户文章是《使用崖山YMP 迁移 Oracle/MySQL 至YashanDB 23.2 验证测试》&#xff08;作者&#xff1a;尚雷&#xff09;&#xff0c…