Java8基础知识
Java8 => 【函数式编程(functional programming)】
主要特性:
- Lambda表达式(Lambda Expression)
- 方法引用(Method Reference)
- 流(Stream)
Lambda表达式
函数式接口是一种包含单一抽象方法(single abstract method)的接口。
- Runnable接口的匿名内部类实现
public class RunnableDemo{ public static void main(String[] args){ new Thread(new Runnable() { @Override public void run(){ System.out.println("inside runnable using an anonymous inner class"); } }).start(); } }
方法引用
使用方法引用(Method Reference)来访问某个现有的方法,并将其作为lambda表达式进行处理。
Lambda表达式本质上是【将方法作为对象】进行处理,那么方法引用就是将现有方法作为Lambda表达式进行处理。
Eg: java.lang.Iterable接口的forEach方法传入Consumer作为参数。Consumer可以作为lambda表达式或方法引用来实现。
Stream.of(3, 1, 4, 1, 5, 9).forEach(x -> System.out.println(x)); Stream.of(1, 2, 3, 4, 5).forEach(System.out::println); Consumer<Integer> printer = System.out::println; Stream.of(1, 2, 3, 4, 5, 6, 7, 8).forEach(printer);
流依次产生一系列元素,但不会将他们存储在任何为止,也不会对原始源进行修改。
@Slf4j public class Demo01 { public static void main(String[] args) { List<Double> myRandomSeed = Stream.generate(Math::random) .limit(10) .map(x -> Math.round(x * Math.pow(10, 2)) / Math.pow(10, 2)) .collect(Collectors.toList()); // [0.46, 0.24, 0.17, 0.18, 0.11, 0.31, 0.04, 0.51, 0.14, 0.18] System.out.println(myRandomSeed); /* * Stream接口定义的generate方法传入Supplier作为参数。Supplier是一个函数式接口 * 其单一抽象方法get不传入任何参数且只生成一个结果。 * Math累的random方法与get方法的签名相互兼容,因为random方法同样不传入任何参数, * 且产生一个0 - 1 之间,均匀分布的双精度伪随机数。 * 方法引用 Math::random表示该方法是Supplier接口的实现。 * * Stream.generate方法产生的是一个无限流(infinite stream) **/ } }
语法
方法引用包括以下三种形式,其中一种存在一定的误导性。
-
object::instanceMethod : 引用特定对象的实例方法, eg: System.out::println
-
Class:staticMethod: 引用静态方法,eg: Math::max
-
Class::instanceMethod: 调用特定类型的任意对象的实例方法,eg: String::length
最后一种形式我们说Java开发中一般类名只能调用Σ(っ °Д °;)静态方法。Lambda表达式和方法引用在任何情况下都不能脱离上下文存在。
// 相当于System.out::println x -> System.out.println(x) 上下文提供了x的值,其被用作方法的参数 // 静态方法max与之类似相当于Math::max (x,y) -> Math.max(x,y) 此时,上下文需要提供两个参数,Lambda表达式返回较大的参数。 x -> x.length() ===> 相当于 String::length 当上下文提供x的值时,它将用作方法的目标而非参数。
从类引用(class reference)调用多参数实例方法
List<String> strings = Arrays.asList("this", "is", "a", "list", "of", "strings"); List<String> sorted = strings.stream() .sorted((s1, s2) -> s1.compareTo(s2)) .collect(Collectors.toList()); List<String> sorted = strings.stream() .sorted(String::compareTo) .collect(Collectors.toList()); 方法引用及其等效的Lambda表达式 Stream接口定义的sorted方法传入Comparator<T>作为参数, 单一抽象方法为int compare(String other)。 sorted方法将每队字符串提供给比较器,并根据返回整数的符号对它们进行排序
使用方法引用在String上调用length方法
Stream.of("this", "is", "a", "stream", "of", "strings")
.map(String::length) // 程序调用length方法每个字符串转换为一个整数,然后打印所有结果。
.forEach(System.out::println)
- 通过类名访问实例方法
- 通过对象应用访问实例方法
方法引用本质上属于Lambda表达式的一种简化语法。
构造函数引用
将方法引用作为流的流水线(stream pipeline)的一部分,以实例化某个对象。
eg: 将一份人员列表 转换为 人员姓名列表
List<String> names = people.stream() .map(per -> per.getName()) .collect(Collectors.toList()); // Another method List<String> names = people.stream() .map(Person::getName()) .collect(Collectors.toList()); package com.huida.app.java8.unit01; import lombok.Data; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; /** * @author wangzhuangzhuang * @DESC: * @date 2022-02-01 23:13 */ @Data class Person{ private String name; public Person(){} // 复制构造函数(copy constructor) 传入一个Person参数,并返回一个具有相同特性的新Person // 如果需要将流代码从原始实例中分离传来,复制构造函数将非常有用。 // eg: 有一个人员列表,=》转换为流 =》 再转换为列表 =》那么引用不会发生变化 public Person(Person p){ this.name = p.name; } public Person(String name){ this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } public class DemoTest02 { public static void main(String[] args) { // ================================================================================================================ // 将字符串转换为Person实例 List<String> names = Arrays.asList("Grace Hopper", "Barbara Liskov", "Ada LoveLace", "Karen Spark Jones"); List<Person> people = names.stream() .map(name -> new Person(name)) // .map(Person::new) .collect(Collectors.toList()); // [Person(name=Grace Hopper), Person(name=Barbara Liskov), Person(name=Ada LoveLace), Person(name=Karen Spark Jones)] System.out.println(people); // =============================================================================================================== // 将列表转换为流,再转换回列表 Person before = new Person("Grace Hopper"); List<Person> peoplePlus = Stream.of(before) .collect(Collectors.toList()); Person after = peoplePlus.get(0); System.out.println("before == after: " + (before == after)); before.setName("Grace Murray Hopper"); System.out.println("after's name: " + after.getName()); // 使用复制构造函数 // =============================================================================================================== List<Person> peoplePlus001 = Stream.of(before) .map(Person::new) // 通过复制构造函数来切断两者之间的连接 .collect(Collectors.toList()); after = peoplePlus001.get(0); System.out.println("after == before: " + (before == after)); // after == before: false System.out.println("before's name: "+ before.getName()); System.out.println("after's name: " + after.getName()); } }
函数式接口
Java8 引入的函数式接口是一种包含单一抽象方法的接口,可以作为Lambda表达式或方法引用的目标
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具