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

浙公网安备 33010602011771号