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表达式或方法引用的目标

posted @   Felix_Openmind  阅读(72)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
*{cursor: url(https://files-cdn.cnblogs.com/files/morango/fish-cursor.ico),auto;}
点击右上角即可分享
微信分享提示