Java 8革新:现代编程的全新标准与挑战

在这里插入图片描述

文章目录

    • 一、方法引用
    • 二、接口默认方法
    • 三、接口静态方法
    • 四、集合遍历forEach()方法

一、方法引用

方法引用是Java 8中一种简化Lambda表达式的方式,通过直接引用现有方法来代替Lambda表达式。

方法引用使得代码更加简洁和易读,特别是在处理函数式接口时,可以替代相对冗长的Lambda表达式,提高了代码的可维护性和可读性。

方法引用通常可以分为以下几种类型:

  • 静态方法引用:引用某个类的静态方法。ClassName::staticMethodName
  • 实例方法引用:引用某个对象的实例方法。objectInstance::instanceMethodName
  • 构造方法引用:引用类的构造方法来创建该类的实例。ClassName::new
  1. 静态方法引用

定义一个函数式接口,定义一个抽象方法 convert,接收一个类型为 F 的参数,并返回一个类型为 T 的结果。

@FunctionalInterface
interface Converter<F, T> {T convert(F from);
}

有一个静态方法 StringHelper 中的静态方法 toUpperCase

class StringHelper {public static String toUpperCase(String str) {return str.toUpperCase();}
}

使用静态方法引用来创建一个 Converter 实例。

/*** StringHelper::toUpperCase 就是静态方法引用,它引用了 StringHelper 类的 toUpperCase 方法,该方法的签名与 Converter 接口中的 convert 方法兼容*/
Converter<String, String> converter = StringHelper::toUpperCase;
String convertedStr = converter.convert("hello");
System.out.println(convertedStr); // 输出: 
HELLO
  1. 实例方法引用

定义一个类 StringUtils,有一个实例方法 startsWithIgnoreCase

class StringUtils {public boolean startsWithIgnoreCase(String str, String prefix) {// 检查一个字符串是否以另一个字符串开头(忽略大小写)return str.toLowerCase().startsWith(prefix.toLowerCase());}
}

使用实例方法引用来创建一个 BiPredicate 实例:

/*** 方法引用允许我们在 BiPredicate 接口的上下文中使用 startsWithIgnoreCase 方法作为一个函数,第一个参数作为方法的调用者(即 stringUtils 对象),第二个参数作为方法的参数传递*/
StringUtils stringUtils = new StringUtils();// 使用实例方法引用创建 BiPredicate 实例
BiPredicate<String, String> startsWithIgnoreCase = stringUtils::startsWithIgnoreCase;// 测试 startsWithIgnoreCase 方法引用的效果,调用 test 方法来检查字符串 "Java" 是否以 "ja" 开头(忽略大小写)
boolean result = startsWithIgnoreCase.test("Java", "ja");
System.out.println(result); 
// 输出:
true
  1. 构造方法引用

定义一个类 Person,它有一个构造方法 Person(String name, int age)

class Person {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}
}

使用构造方法引用来创建一个 Supplier 实例。

// 使用构造方法引用创建 Supplier 实例
Supplier<Person> personSupplier = Person::new;
// 获取 Person 对象
Person person = personSupplier.get();// 设置 Person 对象的属性
person = new Person("Alice", 30);
System.out.println(person.getName() + ", " + person.getAge());// 输出: 
Alice, 30

在这里,Person::new 是构造方法引用,它引用了 Person 类的构造方法,根据 Supplier 的函数签名,Java 编译器会自动推断使用哪个构造方法。

是不是感觉构造方法引用有点多余,这样有什么好处吗?为什么不直接new一个构造函数,这样不显得多此一举吗 ?

使用构造方法引用和 Supplier 接口结合起来的好处

  1. 延迟实例化和懒加载
    • 当你使用构造方法引用创建 Supplier 实例时,实际的对象并没有立即被创建。
    • 只有在调用 Supplierget() 方法时,才会真正创建对象。这种方式可以延迟对象的实例化,直到真正需要使用它时。
  2. 与函数式接口的兼容性
    • Supplier 是一个函数式接口,它通常用于表示一个供给型的操作,它不接受任何参数,返回一个指定类型的结果。
    • 使用构造方法引用可以非常自然地与函数式接口一起使用,因为构造方法引用本质上就是一种函数式的表达方式。
  3. 更加清晰和简洁的代码
    • 使用构造方法引用可以使代码更加简洁和易于理解,特别是在需要创建大量对象或者与函数式编程范式结合使用时。它减少了重复的代码,提高了代码的可读性。
  4. 支持方法引用的优势
    • 构造方法引用是方法引用的一种特殊形式,它直接引用类的构造方法。这允许你像引用方法一样引用构造方法,从而提供了更高的灵活性和可复用性。

二、接口默认方法

Java 8 引入了接口的默认方法,这是一种在接口中定义具有默认实现的方法的方式。默认方法允许接口在不破坏现有实现的情况下,向现有的接口添加新的方法。

特点和用途

  1. 默认实现
    • 默认方法在接口中可以提供方法的具体实现,可以直接在接口中定义,并提供一个默认的方法体。
  2. 向后兼容性
    • 默认方法的引入使得现有的接口能够以向后兼容的方式进行扩展。
    • 当接口被新方法扩展时,实现这个接口的所有类都不需要修改现有代码。
  3. 多继承问题的解决
    • 默认方法允许接口在不引入抽象类的情况下定义方法的具体实现。
    • 一个类可以实现多个接口并继承多个默认方法,解决了传统接口不支持多继承的问题。
  4. 接口的演进
    • 默认方法使得接口在 Java 8 中具备了更强的功能,可以像抽象类一样拥有一些默认行为,同时保持其灵活性和扩展性。
interface Vehicle {// 抽象方法void start(); // 默认方法default void stop() {System.out.println("Vehicle stopped"); }
}class Car implements Vehicle {@Overridepublic void start() {System.out.println("Car started");}// 可选:覆盖默认方法@Overridepublic void stop() {System.out.println("Car stopped");}
}public class Main {public static void main(String[] args) {Vehicle car = new Car();// 输出: Car startedcar.start(); // 输出: Car stoppedcar.stop();  }
}

一个类实现了多个接口,这些接口中有相同签名的默认方法(包括继承关系),那么编译器会要求显式地覆盖冲突的默认方法,以消除二义性。

冲突主要存在的情况

  1. 同名同参的默认方法:如果一个类实现了多个接口,这些接口中有相同签名(方法名和参数列表相同)的默认方法,则需要在实现类中手动提供具体实现,从而消除二义性。
  2. 接口继承冲突:如果一个接口继承了另一个接口,并且提供了一个与父接口中默认方法签名相同但默认实现不同的方法,实现类必须覆盖这个方法来解决二义性。
interface InterfaceA {default void greet() {System.out.println("Hello from InterfaceA");}
}interface InterfaceB {default void greet() {System.out.println("Hello from InterfaceB");}
}// 实现类实现了多个接口,这些接口中有同名的默认方法 greet()
class MyClass implements InterfaceA, InterfaceB {// 需要手动实现 greet() 方法,消除二义性@Overridepublic void greet() {// 可以选择调用 InterfaceA 的默认实现InterfaceA.super.greet(); // 也可以自己实现}
}public class Main {public static void main(String[] args) {MyClass obj = new MyClass();obj.greet(); }
}// 输出: 
Hello from InterfaceA

三、接口静态方法

接口静态方法是Java 8引入的一个重要特性,它们扩展了接口的功能,使得接口可以包含静态的方法实现。这种方法通常用于定义一些通用的工具方法,或者提供与接口实例无关的共享代码。静态方法的引入使得Java接口在语法上更加灵活和功能强大。

特点和用途

  1. 方法实现
    • 接口静态方法可以直接在接口中提供方法的具体实现。这些方法使用 static 关键字声明,并且可以有方法体。
  2. 工具方法
    • 静态方法通常用于提供一些通用的工具方法,这些方法与接口的实例无关,直接通过接口名调用。
  3. 代码重用
    • 静态方法可以在接口中定义一些常见的实用方法,以便多个类或实现接口的类共享和重用这些方法。
  4. 不可被继承
    • 接口的静态方法不能被实现该接口的类所继承或覆盖。这使得静态方法的行为与类的静态方法有所不同,类的静态方法可以被继承或隐藏。
interface UtilityInterface {// 静态方法static void printMessage(String message) {System.out.println("Message from interface: " + message);}// 抽象方法void processData(String data);
}class MyClass implements UtilityInterface {@Overridepublic void processData(String data) {System.out.println("Processing data: " + data);}
}public class Main {public static void main(String[] args) {// 调用静态方法UtilityInterface.printMessage("Hello, world!"); MyClass obj = new MyClass();obj.processData("Sample Data");}
}

四、集合遍历forEach()方法

集合类(如List、Set、Map等)引入了一个新的方法 forEach(),用于简化集合的遍历操作。这个方法可以在集合类的实例上直接调用,接受一个函数式接口的实现作为参数,用来定义遍历集合时的操作。

  1. List 遍历
import java.util.Arrays;
import java.util.List;public class Main {public static void main(String[] args) {List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");// 使用 forEach() 遍历输出每个元素names.forEach(name -> System.out.println(name));// 也可以使用方法引用names.forEach(System.out::println);}
}
  1. Set 遍历
import java.util.HashSet;
import java.util.Set;public class Main {public static void main(String[] args) {Set<Integer> numbers = new HashSet<>();numbers.add(1);numbers.add(2);numbers.add(3);// 使用 forEach() 遍历输出每个元素numbers.forEach(number -> System.out.println(number));}
}
  1. Map 遍历
import java.util.HashMap;
import java.util.Map;public class Main {public static void main(String[] args) {Map<Integer, String> map = new HashMap<>();map.put(1, "One");map.put(2, "Two");map.put(3, "Three");// 使用 forEach() 遍历输出每个键值对map.forEach((key, value) -> System.out.println(key + " -> " + value));}
}

注意事项:

  • forEach() 方法不能保证集合元素的顺序,具体取决于集合的实现类。
  • 在遍历过程中,不建议修改集合的结构,这可能会导致 ConcurrentModificationException 异常。

好的木材并不在顺境中生长,风越强,树越壮

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大数据专业创新人才培养体系的探索与实践

一、引言 随着大数据技术的迅猛发展&#xff0c;其在各行各业中的应用日益广泛&#xff0c;对大数据专业人才的需求也日益增长。我国高度重视大数据产业的发展&#xff0c;将大数据作为国家战略资源&#xff0c;推动大数据与各行业的深度融合。教育部也积极响应国家战略&#…

JVM:字节码文件

文章目录 一、Java虚拟机的组成二、字节码文件的组成1、基本信息2、常量池3、字段4、方法5、属性 三、常用的字节码工具1、javap -v 命令2、jclasslib插件3、阿里arthas 一、Java虚拟机的组成 二、字节码文件的组成 1、基本信息 魔数、字节码文件对应的Java版本号访问标识&am…

Docker 使用基础(2)—镜像

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;秒針を噛む—ずっと真夜中でいいのに。 0:34━━━━━━️&#x1f49f;──────── 4:20 &#x1f504; ◀️ ⏸ …

Vue组件通信props和$emit用法

父传子&#xff0c;通过props 子传父&#xff0c;通过$emit App.vue <template><div class"app" style"border: 3px solid #000; margin: 10px">我是APP组件<!-- 1.给组件标签&#xff0c;添加属性方式 赋值 --><!-- 添加属性传值 …

【java算法专场】双指针(下)

611. 有效三角形的个数 目录 611. 有效三角形的个数 算法思路 算法代码 LCR 179. 查找总价格为目标值的两个商品 算法思路 算法代码 HashSet 双指针 15. 三数之和 算法思路 算法代码 18. 四数之和 ​编辑算法思路 算法代码 611. 有效三角形的个数 算法思路 算法…

前端面试题(CSS篇六)

一、浏览器如何判断是否支持 webp 格式图片 &#xff08;1&#xff09;宽高判断法。通过创建image对象&#xff0c;将其src属性设置为webp格式的图片&#xff0c;然后在onload事件中获取图片的宽高&#xff0c;如果能够获取&#xff0c;则说明浏览器支持webp格式图片。如果不能…

IAR 编译优化等级详解

目录 1.编译时优化器何时介入 2.编译优化等级汇总 3.优化项解读 3.1 代码移动 3.2 函数内联 3.3 循环交换 3.4 循环展开 3.5 公用表达式消除 3.6 链接阶段的优化 4 小结 大家好&#xff0c;这里是快乐的肌肉。 最近在迁移工程到IAR编译器上&#xff0c;发现编译优化…

AI赛道成功的“小”AI平台,都在做什么?

在深入了解30多家跨界拓展AI赛道业务的企业后&#xff0c;我们发现大家对目前的AI市场存在一定程度的误解&#xff1a;即认为在AI领域想要分一杯羹&#xff0c;只需要搞几个API&#xff0c;把大语言模型、绘画、视频、数字人等功能都放上去&#xff0c;可能就有机会占一席之地了…

递归 迷宫问题-java

1&#xff09;findWay方法是为了找出走出迷宫的路径&#xff0c;找到返回true&#xff0c;否则返回false 2&#xff09;&#xff08;i&#xff0c;j&#xff09;是老鼠的位置&#xff0c;初始化的位置为&#xff08;1&#xff0c;1&#xff09; 3&#xff09;因为是递归找路&am…

2024年网络监控软件排名|10大网络监控软件是哪些

网络安全&#xff0c;小到关系到企业的生死存亡&#xff0c;大到关系到国家的生死存亡。 因此网络安全刻不容缓&#xff0c;在这里推荐网络监控软件。 2024年这10款软件火爆监控市场。 1.安企神软件&#xff1a; 7天免费试用https://work.weixin.qq.com/ca/cawcde06a33907e6…

【Linux】一文看懂Linux静态库和动态库

文章目录 一、静态库&#xff08;Static Library&#xff09;二、动态库&#xff08;Dynamic Library&#xff09;三、静态库和动态库的比较四、静态库的制作与使用五、动态库的制作与使用六、如何区分链接的是动态库还是静态库 在Linux系统编程中&#xff0c;库是一组预先编写…

【全面讲解下Foxit Reader】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

3年经验的B端产品经理,应该是什么水平?

问你一个问题&#xff1a;你觉得3年经验的B端产品经理&#xff0c;应该是什么水平&#xff1f;很多朋友可能也没有仔细想过&#xff0c;自己3年后应该达到一个什么水平&#xff1f;能做什么体量的业务&#xff1f;要能拿多少薪资&#xff1f; 前几天和一个B端产品经理聊天&…

SQL之delete、truncate和drop区别

MySQL删除数据的方式都有哪些&#xff1f; 常用的三种删除方式&#xff1a;通过 delete、truncate、drop 关键字进行删除&#xff1b;这三种都可以用来删除数据&#xff0c;但场景不同。 一、从执行速度上来说 drop > truncate >> DELETE;二、从原理上讲 1、DELET…

ctfshow-web入门-文件上传(web161、web162、web163)远程包含

目录 1、web161 2、web162 3、web163 1、web161 先传配置文件&#xff0c;可以上传成功 因为我前面给的 .user.ini 都是带了图片头 GIF89a 的&#xff0c;前面的题这个图片头可以去掉&#xff0c;但是在这里如果去掉是不行的。 因此后面上传的东西我们都带上这个图片头&…

FPGA程序设计

在设计FPGA时&#xff0c;多运用模块化的思想取设计模块&#xff0c;将某一功能设计成module。 设计之前要先画一下模块设计图&#xff0c;列出输入输出接口&#xff0c;再进一步设计内部功能。 状态机要画图&#xff0c;确定每个状态和状态之间怎么切换。状态用localparam定…

宏碁F5-572G-59K3笔记本笔记本电脑拆机清灰教程(详解)

1. 前言 我的笔记本开机比较慢&#xff0c;没有固态&#xff0c;听说最近固态比较便宜&#xff0c;就想入手一个&#xff0c;于是拆笔记本看一下有没有可以安的装位置。&#xff08;友情提示&#xff0c;在拆机之前记得洗手并擦干&#xff0c;以防静电损坏电源器件&#xff09…

视频版权音乐处理☞AI分离人声、音效、背景音乐的需求和进展-2024

随着互联网的普及和短视频的兴起&#xff0c;视频内容的全球各大平台分发越来越普遍。然而&#xff0c;不同国家和地区的音乐版权、不同社媒平台拥有的版权和处理政策都存在差异&#xff0c;因此同一个视频在多渠道分发的时候就会产生版权侵权风险。如何既能满足全球多渠道、多…

【UE5】调用ASR接口,录制系统输出。录制音频采样率不匹配

暂时测出window能用。阿里的ASR接口当前仅支持8000和16000。UE默认采样44100。

补码一位乘法原理(布斯编码详讲)

最近在看补码乘法的时候&#xff0c;感觉到很奇怪的一点&#xff0c;那就是补码的一位乘法&#xff0c;就是上网查了大量的资料都没有理解到它真正的原理&#xff0c;总感觉还是不会。那么&#xff0c;补码乘法的原理到底是什么呢&#xff1f;而让我们一直困惑的点是哪里呢&…