1 函数式编程思想
1.1 概述
-
在数学中,函数(y = f(x))就是有输入量、输出量的一套计算方案,也就是“拿什么东西做什么事情”。编程中的函数,也有类似的概念,你调用我的时候,给我实参为形参赋值,然后通过运行方法体,给你一个返回结果。对于调用者来说,关注的是这个方法具备什么样的功能。相对而言,面向对象过分强调“必须通过对象的形式来做事情”,而函数式思想则尽量忽略面向对象的复杂语法--
强调做什么,而不是以什么形式做
。 -
面向对象思想:做一件事情,找一个能解决这个事情的对象,调用对象的方法,完成事情。
-
函数式编程思想:只要能获取到结果,谁去做不重要,重视的是结果,不是过程。
-
JDK 8引入了Lambda表示式之后,Java也开始支持函数式编程。
-
Lambda表达式不是Java最早使用的,很多语言支持很早就支持Lambda,例如:C++、C#、Python、Scala等。如果有JavaScript或Python的语言基础,对理解Lambda表达式有很大的帮助,可以说Lambda表达式其实就是实现SAM(Single Abstract Method,即接口中只能有一个抽象方法)接口的语法糖,使得Java也算是支持函数式编程的语言。Lambda写得好可以极大的减少代码冗余,同时可读性也好过冗余的匿名内部类。
注意:
-
**"语法糖"**是指使用更加方便,但是原理不变的代码语法。例如在遍历集合时使用的for-each语法,其实
底层的实现原理仍然是迭代器,这便是“语法糖”。 -
从应用层面来讲,Java中的Lambda可以被当做是匿名内部类的“语法糖”,但是二者在原理上是不同的。
1.2 冗余的匿名内部类
- 当需要启动一个线程去完成任务的时候,通过会通过
java.lang.Runnable
接口来定义任务内容,并使用java.lang.Thread类来启动该线程,代码如下:
package top.open1024.demo1;
/**
* @author open1024
* @version 1.0
* @since 2021-10-09 09:09
*/
public class Test {
public static void main(String[] args) {
// 匿名内部类
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("多线程任务执行!!!!");
}
};
// 启动线程
new Thread(runnable).start();
}
}
-
本着“一切皆对象”的思想,这样的做法无可厚非的:首先创建
Runnable
接口的匿名内部类对象来指定任务内容,然后将其交给一个线程来启动。 -
代码分析:
-
对于Runnable的匿名内部类的用法,可以分析出以下几点:
-
- ①
Thread
类需要Runnable
接口作为参数,其中的抽象run
方法是用来指定线程任务内容的核心。
- ①
-
- ② 为了指定
run
的方法体,不得不
需要Runnable
接口的实现类。
- ② 为了指定
-
- ③ 为了省去定义一个
Runnable
实现类的麻烦,不得不
实现匿名内部类。
- ③ 为了省去定义一个
-
- ④ 为了覆盖重写抽象
run
方法,其方法名称、方法参数、方法的返回值不得不
重写一遍,且不能写错。
- ④ 为了覆盖重写抽象
-
但是,实际上,
方法体才是关键所在
。
1.3 编程思想的转换
-
面向对象的编程思想:关注的是怎么做,由谁做?
-
函数式编程思想:更多关注的是做什么?
-
我们真的希望创建一个匿名内部类对象吗?当然不,我们只是为了完成这件事情(语法的限制)
不得不
创建一个对象。我们真正希望做的事情是:将run
方法体内的代码传递给Thread
类知晓。 -
传递一段代码
--这才是我们真正的目的。而创建对象只是受限于面向对象的语法而不得不采用的一种手段方式。那么,有没有更加简单的办法?如果我们将关注点从怎么做,由谁做?
回归到做什么
的本质上,就会发现只要能够更好的达成目的,过程和形式并不重要(成王败寇)。 -
生活举例:
-
当我们需要从北京到上海的时候,可以选择高铁、汽车、骑行甚至徒步。我们真正的目的是到达上海,而如何到达上海的形式并不重要,所以我们一直在探索有没有比高铁更好的方式--搭乘飞机。
- 而现在这种飞机(甚至是飞船)已经诞生。
- 2014年3月,Oracle发布的JDK 8,加入了Lambda表达式的重量级新特性,为我们打开了新世界的大门。
1.4 体验Lambda的优雅写法
- 借助JDK 8的全新语法,上述
Runnable
接口的匿名内部类写法可以通过更加简单的Lambda表达式达到同等效果:
package top.open1024.demo2;
/**
* @author open1024
* @version 1.0
* @since 2021-10-09 09:33
*/
public class Test {
public static void main(String[] args) {
new Thread(() -> System.out.println("多线程任务执行!!!!")).start();
}
}
-
这段代码的执行效果和匿名内部类写法的执行效果一致,可以在JDK8及其以上版本编译通过。从代码的语义可以看出:我们启动的一个线程,而线程的任务内容以一种更加简洁的形式被指定。
-
不再有
不得不创建接口对象
的束缚,不再有抽象方法覆盖重写
的负担,就是这么爽
。
2 Lambda表达式
2.1 函数式接口
2.1.1 概述
-
Lambda表达式其实就是实现SAM(Single Abstract Method,即该接口中有且仅有一个抽象方法,当然该接口中还可以包含非抽象方法)接口的语法糖。
-
其实,只要满足SAM特征的接口就是函数式接口,就可以使用Lambda表达式了,但是如果在声明函数式接口的时候,使用
@FunctionalInterface
注解来声明,那么编译器就会强制检查该接口是否确实有且仅有一个抽象方法,如果不是,将报错。 -
之前学过的SAM接口中,标记了
@FunctionalInterface
注解的接口有:Runnable、Comparator、FileFilter。 -
JDK 8在
java.util.function
包中新增了很多函数式接口,主要分为消费型、供给型、断言型(判断型)、函数型(功能型)。基本上可以满足我们实际的开发,当然,我们也可以自定义函数式接口。
2.1.2 自定义函数式接口
- 语法:
@FunctionalInterface
修饰符 interface 接口名{
[public abstract] 返回值类型 方法名(形参列表);
}
注意:在接口中的抽象方法,可以省略public abstract
关键字的。
- 示例:
package top.open1024.demo3;
/**
* 计算
*
* @author open1024
* @version 1.0
* @since 2021-10-09 11:12
*/
@FunctionalInterface
public interface Calculator {
int calc(int a, int b);
}
package top.open1024.demo3;
/**
* @author open1024
* @version 1.0
* @since 2021-10-09 10:44
*/
public class Test {
public static void main(String[] args) {
calc(1, 2, (a, b) -> a + b); // result = 3
calc(1, 2, (a, b) -> a - b); // result = -1
calc(1, 2, (a, b) -> a * b); // result = 2
calc(1, 2, (a, b) -> a / b); // result = 0
calc(1, 2, (a, b) -> a % b); // result = 1
}
public static void calc(int a, int b, Calculator calc) {
int result = calc.calc(a, b);
System.out.println("result = " + result);
}
}
2.1.3 函数式接口的分类
- 除了我们可以自定义函数式接口外,JDK还给我们内置了一些函数式接口,具体分类如下。
2.1.3.1 消费型接口
- 消费型接口的抽象方法的特点:有形参,但是返回值类型是void。
接口名 | 抽象方法 | 描述 |
---|---|---|
Consumer | void accept(T t) | 接收一个对象用于完成功能 |
BiConsumer<T,U> | void accept(T t, U u) | 接收两个对象用于完成功能 |
DoubleConsumer | void accept(double value) | 接收一个double值 |
IntConsumer | void accept(int value) | 接收一个int值 |
LongConsumer | void accept(long value) | 接收一个long值 |
ObjDoubleConsumer | void accept(T t, double value) | 接收一个对象和一个double值 |
ObjIntConsumer | void accept(T t, int value) | 接收一个对象和一个int值 |
ObjLongConsumer | void accept(T t, long value) | 接收一个对象和一个long值 |
2.1.3.2 供给型接口
- 供给型接口的抽象方法的特点:无形参,但是有返回值。
接口名 | 抽象方法 | 描述 |
---|---|---|
Supplier | T get() | 返回一个对象 |
BooleanSupplier | boolean getAsBoolean() | 返回一个boolean值 |
DoubleSupplier | double getAsDouble() | 返回一个double值 |
IntSupplier | int getAsInt() | 返回一个int值 |
LongSupplier | long getAsLong() | 返回一个long值 |
2.1.3.3 断言型接口
- 断言型接口的特点:有形参,但是返回值类型是boolean。
接口名 | 抽象方法 | 描述 |
---|---|---|
Predicate | boolean test(T t) | 接收一个对象 |
BiPredicate<T,U> | boolean test(T t, U u) | 接收两个对象 |
DoublePredicate | boolean test(double value) | 接收一个double值 |
IntPredicate | boolean test(int value) | 接收一个int值 |
LongPredicate | boolean test(long value) | 接收一个long值 |
2.3.3.4 函数型接口
- 函数型接口的特点:有形参,有返回值。
接口名 | 抽象方法 | 描述 |
---|---|---|
Function<T,R> | R apply(T t) | 接收一个T类型对象,返回一个R类型对象结果 |
UnaryOperator | T apply(T t) | 接收一个T类型对象,返回一个T类型对象结果 |
DoubleFunction | R apply(double value) | 接收一个double值,返回一个R类型对象 |
IntFunction | R apply(int value) | 接收一个int值,返回一个R类型对象 |
LongFunction | R apply(long value) | 接收一个long值,返回一个R类型对象 |
ToDoubleFunction | double applyAsDouble(T value) | 接收一个T类型对象,返回一个double |
ToIntFunction | int applyAsInt(T value) | 接收一个T类型对象,返回一个int |
ToLongFunction | long applyAsLong(T value) | 接收一个T类型对象,返回一个long |
DoubleToIntFunction | int applyAsInt(double value) | 接收一个double值,返回一个int结果 |
DoubleToLongFunction | long applyAsLong(double value) | 接收一个double值,返回一个long结果 |
IntToDoubleFunction | double applyAsDouble(int value) | 接收一个int值,返回一个double结果 |
IntToLongFunction | long applyAsLong(int value) | 接收一个int值,返回一个long结果 |
LongToDoubleFunction | double applyAsDouble(long value) | 接收一个long值,返回一个double结果 |
LongToIntFunction | int applyAsInt(long value) | 接收一个long值,返回一个int结果 |
DoubleUnaryOperator | double applyAsDouble(double operand) | 接收一个double值,返回一个double |
IntUnaryOperator | int applyAsInt(int operand) | 接收一个int值,返回一个int结果 |
LongUnaryOperator | long applyAsLong(long operand) | 接收一个long值,返回一个long结果 |
BiFunction<T,U,R> | R apply(T t, U u) | 接收一个T类型和一个U类型对象,返回一个R类型对象结果 |
BinaryOperator | T apply(T t, T u) | 接收两个T类型对象,返回一个T类型对象结果 |
ToDoubleBiFunction<T,U> | double applyAsDouble(T t, U u) | 接收一个T类型和一个U类型对象,返回一个double |
ToIntBiFunction<T,U> | int applyAsInt(T t, U u) | 接收一个T类型和一个U类型对象,返回一个int |
ToLongBiFunction<T,U> | long applyAsLong(T t, U u) | 接收一个T类型和一个U类型对象,返回一个long |
DoubleBinaryOperator | double applyAsDouble(double left, double right) | 接收两个double值,返回一个double结果 |
IntBinaryOperator | int applyAsInt(int left, int right) | 接收两个int值,返回一个int结果 |
LongBinaryOperator | long applyAsLong(long left, long right) | 接收两个long值,返回一个long结果 |
2.2 Lambda表达式的语法
-
Lambda表达式是用来给
函数式接口
的变量或形参赋值使用的。 -
本质上,Lambda表达式是用于实现
函数式接口
的抽象方法
。 -
语法:
(形参列表) -> {Lambda体}
-
说明:
-
(形参列表)
:就是要赋值的函数式接口的抽象方法的(形参列表)
。
-
{Lambda体}
:就是实现这个抽象方法的方法体。
-
->
:Lambda操作符。
-
优化:
-
- 当
{Lambda体}
只有一条语句的时候,可以省略{}
和{;}
。
- 当
-
- 当
{Lambda体}
只有一条语句的时候,并且这个语句还是return语句的时候,return也可以省略,但是如果{;}
没有省略,那么return是不可以省略的。
- 当
-
(形参列表)
的类型可以省略。
-
- 当
(形参列表)
的形参个数只有一个,那么可以将数据类型和()
一起省略,但是形参名不能省略。
- 当
-
- 当
(形参列表)
是空参的时候,()
不能省略。
- 当
-
示例:
package top.open1024.demo4;
import java.util.function.IntBinaryOperator;
/**
* @author open1024
* @version 1.0
* @since 2021-10-09 11:00
*/
public class Test {
public static void main(String[] args) {
useIntBinaryOperator(1, 2, (a, b) -> a + b);
}
public static void useIntBinaryOperator(int a, int b, IntBinaryOperator operator) {
int result = operator.applyAsInt(a, b);
System.out.println("result = " + result);
}
}
- 示例:
package top.open1024.demo5;
import java.util.Set;
import java.util.TreeSet;
/**
* @author open1024
* @version 1.0
* @since 2021-10-09 13:36
*/
public class Test {
public static void main(String[] args) {
Set<Integer> set = new TreeSet<>((a, b) -> a - b);
set.add(10);
set.add(100);
set.add(-20);
set.add(5);
set.add(1);
System.out.println("set = " + set); // set = [-20, 1, 5, 10, 100]
}
}
- 示例:
package top.open1024.demo6;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* @author open1024
* @version 1.0
* @since 2021-10-09 13:41
*/
public class Test {
public static void main(String[] args) {
userConsumer("abc", s -> System.out.println(s));
useSupplier(() -> String.valueOf(Math.random()));
usePredicate(Arrays.asList("a", "b", "c"), (s) -> s.equals("a"));
useFunction(1, (i) -> String.valueOf(i));
}
public static void userConsumer(String str, Consumer<String> consumer) {
consumer.accept(str);
}
public static void useSupplier(Supplier<String> supplier) {
String s = supplier.get();
System.out.println(s);
}
public static void usePredicate(List<String> list, Predicate<String> predicate) {
for (String s : list) {
if (predicate.test(s)) {
System.out.println(s);
}
}
}
public static void useFunction(Integer num, Function<Integer, String> function) {
String apply = function.apply(num);
System.out.println(apply);
}
}
2.3 Lambda表达式的练习
2.3.1 JDK中的消费型接口
- 在JDK 8中的Collection接口的父接口Iterable接口中增加了一个默认方法,该方法是消费型接口:
public interface Iterable<T> {
// 遍历Collection集合的每个元素
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
...
}
- 在JDK 8中的Map集合中增加了一个默认方法,该方法是消费型接口:
public interface Map<K, V> {
// 遍历Map集合的每一个entry对象
default void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch (IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
action.accept(k, v);
}
}
...
}
- 示例:
package top.open1024.demo7;
import java.util.Arrays;
import java.util.List;
/**
* @author open1024
* @version 1.0
* @since 2021-10-09 13:55
*/
public class Test {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
// 遍历List集合中的每个元素
list.forEach(i -> System.out.println(i));
}
}
- 示例:
package top.open1024.demo8;
import java.util.HashMap;
/**
* @author open1024
* @version 1.0
* @since 2021-10-09 14:40
*/
public class Test {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put("1", "java");
map.put("2", "c");
map.put("3", "python");
map.put("4", "vb");
map.put("5", "c#");
// 遍历Map中的每个元素
map.forEach((k, v) -> System.out.println(k + ":" + v));
}
}
2.3.2 JDK中的供给型接口
- 在JDK 8中增加Stream接口,
java.util.stream.Stream<T>
是一个数据流,该方法是供给型接口,可以创建Stream对象:
public interface Stream<T> extends BaseStream<T, Stream<T>> {
public static<T> Stream<T> generate(Supplier<? extends T> s) {
Objects.requireNonNull(s);
return StreamSupport.stream(
new StreamSpliterators.InfiniteSupplyingSpliterator.OfRef<>(Long.MAX_VALUE, s), false);
}
...
}
- 示例:
package top.open1024.demo9;
import java.util.Random;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-09 14:55
*/
public class Test {
public static void main(String[] args) {
Stream.generate(() -> new Random().nextInt(10) + 1).limit(10).forEach(num -> System.out.println(num));
}
}
2.3.4 JDK中函数型接口
- 在JDK 8中的Map集合增加了很多函数型接口:
public interface Map<K, V> {
// 替换Map中的值
default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
Objects.requireNonNull(function);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch (IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
// ise thrown from function is not a cme.
v = function.apply(k, v);
try {
entry.setValue(v);
} catch (IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
}
}
...
}
- 示例:
package top.open1024.demo10;
/**
* @author open1024
* @version 1.0
* @since 2021-10-09 15:19
*/
public class Employee {
private Integer id;
private String name;
private Double salary;
public Employee() {}
public Employee(Integer id, String name, Double salary) {
this.id = id;
this.name = name;
this.salary = salary;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public Double getSalary() {
return this.salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Employee{" + "name='" + this.name + '\'' + ", id=" + this.id + ", salary=" + this.salary + '}';
}
}
package top.open1024.demo10;
import java.util.HashMap;
import java.util.Map;
/**
* @author open1024
* @version 1.0
* @since 2021-10-09 15:20
*/
public class Test {
public static void main(String[] args) {
Map<Integer, Employee> map = new HashMap<>();
Employee e1 = new Employee(1, "张三", 5000.00);
Employee e2 = new Employee(2, "李四", 15000.00);
Employee e3 = new Employee(3, "王五", 75000.00);
Employee e4 = new Employee(4, "赵六", 7000.00);
Employee e5 = new Employee(5, "田七", 200.00);
map.put(e1.getId(), e1);
map.put(e2.getId(), e2);
map.put(e3.getId(), e3);
map.put(e4.getId(), e4);
map.put(e5.getId(), e5);
// 将工资小于10000元的员工的工资设置为10000
map.replaceAll((k, v) -> {
if (v.getSalary() < 10000) {
v.setSalary(10000.00);
}
return v;
});
map.forEach((k, v) -> System.out.println(k + ":" + v));
}
}
- 示例:
package top.open1024.demo11;
import java.util.HashMap;
import java.util.Map;
/**
* @author open1024
* @version 1.0
* @since 2021-10-09 15:32
*/
public class Test {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("1", "java");
map.put("2", "c");
map.put("3", "python");
map.put("4", "vb");
map.put("5", "c#");
// 将Map中的java替换成JavaEE
map.replaceAll((k, v) -> {
if (v.equals("java")) {
v = "JavaEE";
}
return v;
});
map.forEach((k, v) -> System.out.println(k + ":" + v));
}
}
2.3.5 JDK中的断言型接口
- 在JDK 8中,Collection接口新增了一个断言型接口:
public interface Collection<E> extends Iterable<E> {
// 删除集合中满足指定条件的元素
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
}
- 示例:
package top.open1024.demo12;
import java.util.ArrayList;
import java.util.List;
/**
* @author open1024
* @version 1.0
* @since 2021-10-09 16:02
*/
public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.removeIf(i -> 1 == i);
list.forEach(i -> System.out.println(i));
}
}
2.4 方法引用和构造器引用
2.4.1 概述
-
Lambda表达式是用来简化函数式接口的变量或形参赋值的语法,而方法引用和构造器引用是为了简化Lambda表达式的。
-
当Lambda表达式满足如下的一些特殊情况,还可以再简化:
-
- ① Lambda体只有一条语句,并且是通过调用一个对象(或类)的方法来完成的。
-
-
- 例如:System.out对象,调用println()方法来完成Lambda体。Math类,调用random()静态方法来完成Lambda体。
-
-
- ② Lambda表达式的形参正好是给该方法的实参。
-
-
- 例如:
t -> System.out.println(t)
,()->Math.random()
。
- 例如:
-
2.4.2 方法引用
- 语法:
实例对象名::实例方法
类名::静态方法
类名::实例方法
-
说明:
-
::
是方法引用操作符。
-
- Lambda表达式的形参列表全部在Lambda体中使用了,要么作为调用方法的对象,要么作为调用方法的实参。
-
- 在整个Lambda中没有额外的数据。
-
示例:
package top.open1024.demo13;
import java.util.Arrays;
import java.util.List;
/**
* @author open1024
* @version 1.0
* @since 2021-10-09 16:19
*/
public class Test {
public static void main(String[] args) {
List<Integer> map = Arrays.asList(1, 2, 3, 4, 5);
map.forEach(System.out::println);
}
}
- 示例:
package top.open1024.demo14;
import java.util.Arrays;
/**
* @author open1024
* @version 1.0
* @since 2021-10-09 16:56
*/
public class Test {
public static void main(String[] args) {
String[] arr = {"hello", "world", "java", "c"};
Arrays.sort(arr, String::compareToIgnoreCase);
Arrays.asList(arr).forEach(System.out::println);
}
}
- 示例:
package top.open1024.demo15;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-09 17:01
*/
public class Test {
public static void main(String[] args) {
Stream.generate(Math::random).limit(10).forEach(System.out::println);
}
}
2.4.3 构造器引用
- 语法:
类名::new
数组类型::new
-
说明:
-
- 当Lambda表达式是为了创建一个对象,并且满足Lambda表达式形参,正好是创建给这个对象的构造器的实参列表。
-
- 当Lambda表达式是为了创建一个数组对象,并且满足Lambda表达式形参,正好是创建这个数组对象的长度。
-
示例:
package top.open1024.demo16;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-09 17:20
*/
public class Test {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3);
Stream<int[]> stream1 = stream.map((i) -> new int[i]);
// Lambda表达式
stream1.forEach((i) -> System.out.println(i.length));
System.out.println("---------------------");
Stream<Integer> stream11 = Stream.of(1, 2, 3);
Stream<int[]> stream2 = stream11.map(int[]::new);
// 构造引用
stream2.forEach((i) -> System.out.println(i.length));
}
}
- 示例:
package top.open1024.demo17;
import java.math.BigDecimal;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-09 17:30
*/
public class Test {
public static void main(String[] args) {
Stream<String> stream = Stream.of("1", "2", "3");
Stream<BigDecimal> stream1 = stream.map(s -> new BigDecimal(s));
stream1.forEach(System.out::println);
System.out.println("---------------");
Stream<String> stream11 = Stream.of("1", "2", "3");
Stream<BigDecimal> stream2 = stream11.map(BigDecimal::new);
stream2.forEach(System.out::println);
}
}
3 Stream API
3.1 概述
-
JDK 8有两个重大的改变。第一个是Lambda表达式,另外一个是Stream API。
-
Stream API(java.util.stream)将真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大的提高Java程序员的生产力,让程序员写出高效、干净、简洁的代码。
-
Stream是JDK 8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询,当然,也可以使用Stream API来并行执行操作。换言之,Stream API提供了一种高效且易于使用的处理数据的方式。
-
Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,负责存储数据,Stream流讲的是计算,负责处理数据!”。
注意:
-
① Stream自己不会存储元素。
-
② Stream不会改变源对象,每次处理读会返回一个持有结果的新的Stream。
-
③ Stream操作是延迟执行的,意味着会等到需要结果的时候才执行。
3.2 Stream流的操作步骤
-
① 创建Stream:通过一个数据源(如:集合、数组),获取一个流。
-
② 中间操作:中间操作是个操作链,对数据源的数据进行n次处理,但是在终结操作前,并不会真正的执行。
-
③ 终止操作:一旦执行终止操作,就执行中间操作链,最终产生结果并结束Stream。
3.3 创建Stream
3.3.1 通过集合创建Stream
-
JDK 8中的Collection接口新增了两个获取流的方法:
-
获取一个顺序流:
default Stream<E> stream() {}
- 获取一个并行流:
default Stream<E> parallelStream() {}
- 示例:
package top.open1024.stream.demo1;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/**
* 通过集合创建Stream
*
* @author open1024
* @version 1.0
* @since 2021-10-09 20:31
*/
public class Test {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
// 获取顺序流
Stream<Integer> stream = list.stream();
stream.forEach(System.out::println);
}
}
3.3.2 通过数组创建Stream
- JDK 8中的Arrays新增了静态方法,用来获取Stream流:
public static <T> Stream<T> stream(T[] array) {}
-
重载形式,能够处理对应基本类型的数组:
-
获取一个整型数据流:
public static IntStream stream(int[] array) {}
- 获取一个长整型数据流:
public static LongStream stream(long[] array) {}
- 获取一个浮点型数据流:
public static DoubleStream stream(double[] array) {}
- 示例:
package top.open1024.stream.demo2;
import java.util.Arrays;
import java.util.stream.Stream;
/**
* 通过数组创建Stream
*
* @author open1024
* @version 1.0
* @since 2021-10-09 20:35
*/
public class Test {
public static void main(String[] args) {
String[] arr = {"PHP", "is", "the", "best", "language", "in", "the", "world"};
Stream<String> stream = Arrays.stream(arr);
stream.forEach(System.out::println);
}
}
3.3.3 通过Stream.of()方法创建Stream
- 可以调用Stream类静态方法of()方法,显示的创建一个流:
public static<T> Stream<T> of(T... values){}
public static<T> Stream<T> of(T t) {}
- 示例:
package top.open1024.stream.demo3;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 06:29
*/
public class Test {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3, 4);
System.out.println("stream = " + stream);
}
}
3.3.4 通过无限流创建Stream
- 可以使用Stream类的静方法iterate和generate创建无限流。
public static<T> Stream<T> generate(Supplier<? extends T> s) {}
public static<T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next) {}
- 示例:
package top.open1024.stream.demo4;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 06:35
*/
public class Test {
public static void main(String[] args) {
Stream<Integer> stream = Stream.iterate(1, num -> num + 1);
stream.limit(10).forEach(System.out::println);
}
}
- 示例:
package top.open1024.stream.demo5;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 06:40
*/
public class Test {
public static void main(String[] args) {
Stream<Double> stream = Stream.generate(Math::random);
stream.limit(10).forEach(System.out::println);
}
}
3.4 中间操作
3.4.1 概述
- 多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不执行任何处理,而在终止操作时一次性全部处理完,称为
“惰性求值”
。
3.4.2 filter
- 根据predicate的返回值,过滤某些元素。
Stream<T> filter(Predicate<? super T> predicate);
- 示例:
package top.open1024.stream.demo6;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 06:42
*/
public class Test {
public static void main(String[] args) {
// 创建Stream
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
// 过滤,如果满足条件,就过滤出来;否则,排除掉。
// 生活中:过滤水,当然是过滤水中的杂质,将杂质排除掉。
Stream<Integer> integerStream = stream.filter(i -> i % 2 == 0);
// 终结操作
integerStream.forEach(System.out::println);
}
}
3.4.3 distinct
- 通过流所生成的equals()去除重复元素:
Stream<T> distinct();
- 示例:
package top.open1024.stream.demo7;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 09:05
*/
public class Test {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 1, 2, 3, 4);
Stream<Integer> distinct = stream.distinct();
distinct.forEach(System.out::println);
}
}
3.4.4 limit
- 截断流,使其元素不超过给定数量:
Stream<T> limit(long maxSize);
- 示例:
package top.open1024.stream.demo8;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 09:10
*/
public class Test {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8);
Stream<Integer> limit = stream.limit(5);
limit.forEach(System.out::println);
}
}
3.4.5 skip
- 跳过前n个元素的流,如果流中的元素不足n个,则返回一个空流:
Stream<T> skip(long n);
- 示例:
package top.open1024.stream.demo9;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 09:18
*/
public class Test {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
Stream<Integer> skip = stream.skip(4);
skip.forEach(System.out::println);
}
}
3.4.6 peek
- peek,对每个元素都进行Lambda操作,一般用于debug流。
Stream<T> peek(Consumer<? super T> action);
- 示例:
package top.open1024.stream.demo10;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 09:35
*/
public class Test {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8);
// peek不会终止流,peek属于中间操作
Stream<Integer> peek = stream.peek(i -> System.out.println(i));
long count = peek.count();
System.out.println("count = " + count);
}
}
3.4.7 sorted
- 对流中的数据进行自然排序:
Stream<T> sorted();
- 对流中的数据进行自定义排序:
Stream<T> sorted(Comparator<? super T> comparator);
- 示例:
package top.open1024.stream.demo11;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 09:54
*/
public class Test {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(3, -1, 2, 4, 0, -90, 4, 56);
Stream<Integer> sorted = stream.sorted();
sorted.forEach(System.out::println);
}
}
- 示例:
package top.open1024.stream.demo12;
import java.util.Comparator;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 09:55
*/
public class Test {
public static void main(String[] args) {
Stream<String> stream = Stream.of("a", "b", "c", "d");
Stream<String> sorted = stream.sorted(Comparator.reverseOrder());
sorted.forEach(System.out::println);
}
}
3.4.8 map
- 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
- 示例:
package top.open1024.stream.demo13;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 10:06
*/
public class Test {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
stream = stream.map(i -> i + 1);
stream.forEach(System.out::println);
}
}
- 示例:
package top.open1024.stream.demo14;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 10:10
*/
public class Person {
private String name;
private Integer age;
public Person() {}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return this.age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" + "name='" + this.name + '\'' + ", age=" + this.age + '}';
}
}
package top.open1024.stream.demo14;
import java.util.Arrays;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 10:10
*/
public class Test {
public static void main(String[] args) {
Stream<Person> stream = Arrays.asList(new Person("张三", 18), new Person("李四", 8), new Person("王五", 12)).stream();
Stream<String> nameStream = stream.map(Person::getName);
nameStream.forEach(System.out::println);
}
}
3.4.9 所有中间操作方法列表
方 法 | 描 述 |
---|---|
filter(Predicate p) | 接收 Lambda , 从流中排除某些元素。 |
distinct() | 筛选,通过流所生成元素的equals() 去除重复元素。 |
limit(long maxSize) | 截断流,使其元素不超过给定数量。 |
skip(long n) | 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补。 |
peek(Consumer****action) | 接收Lambda,对流中的每个数据执行Lambda体操作。 |
sorted() | 产生一个新流,其中按自然顺序排序。 |
sorted(Comparator com) | 产生一个新流,其中按比较器顺序排序。 |
map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。 |
mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。 |
mapToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。 |
mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。 |
flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。 |
3.5 终止操作
3.5.1 概述
- 终止操作会从流的流水线生成结果,其结果可以是任何不是流的值,比如:List、Integer,甚至可以是void。流进行了终止操作之后,不能再次使用。
3.5.2 forEach迭代
- 迭代流中的元素:
void forEach(Consumer<? super T> action);
- 示例:
package top.open1024.stream.demo15;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 10:20
*/
public class Test {
public static void main(String[] args) {
Stream.of(1, 2, 3, 4, 5, 6).forEach(System.out::println);
}
}
3.5.3 count
- 返回流所操作的数据的总数:
long count();
- 示例:
package top.open1024.stream.demo16;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 10:23
*/
public class Test {
public static void main(String[] args) {
long count = Stream.of(1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1).distinct().count();
System.out.println("count = " + count); // count = 6
}
}
3.5.4 allMatch
- 检查流所操作的所有元素是否匹配规则:
boolean allMatch(Predicate<? super T> predicate);
- 示例:
package top.open1024.stream.demo17;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 10:25
*/
public class Test {
public static void main(String[] args) {
// 判断流所操作的元素是否都是偶数
boolean allMatch = Stream.of(1, 2, 3, 4, 5, 6).allMatch(i -> i % 2 == 0);
System.out.println("allMatch = " + allMatch); // allMatch = false
}
}
3.5.5 anyMatch
- 判断流所操作的元素是否有一个元素匹配规则:
boolean anyMatch(Predicate<? super T> predicate);
- 示例:
package top.open1024.stream.demo18;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 10:28
*/
public class Test {
public static void main(String[] args) {
// 判断流所操作的元素是否有一个是偶数
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
boolean anyMatch = stream.anyMatch(i -> i % 2 == 0);
System.out.println("anyMatch = " + anyMatch); // anyMatch = true
}
}
3.5.6 FindFirst
- 返回流所操作元素中的第一个元素:
Optional<T> findFirst();
- 示例:
package top.open1024.stream.demo19;
import java.util.Optional;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 10:33
*/
public class Test {
public static void main(String[] args) {
Stream<Integer> distinct = Stream.of(2, 3, 4, 5, 5, 4, 3, 2, 1).distinct();
Optional<Integer> first = distinct.findFirst();
Integer integer = first.get();
System.out.println("integer = " + integer); // integer = 2
}
}
3.5.7 max
- 返回流所操作元素中的最大值:
Optional<T> max(Comparator<? super T> comparator);
- 示例:
package top.open1024.stream.demo20;
import java.util.Optional;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 10:36
*/
public class Test {
public static void main(String[] args) {
Optional<Integer> optional = Stream.of(1, 2, -1, 10, 2).distinct().max(Integer::compareTo);
Integer integer = optional.get();
System.out.println("integer = " + integer); // integer = 10
}
}
3.5.8 reduce
- 可以将流中元素反复结合起来,得到一个值。返回 T:
T reduce(T identity, BinaryOperator<T> accumulator);
- 可以将流中元素反复结合起来,得到一个值。返回
Optional<T>
:
Optional<T> reduce(BinaryOperator<T> accumulator);
- 示例:
package top.open1024.stream.demo22;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 10:41
*/
public class Test {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Integer reduce = stream.reduce(0, Integer::sum);
System.out.println("reduce = " + reduce); // reduce = 15
}
}
- 示例:
package top.open1024.stream.demo23;
import java.util.Optional;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 10:42
*/
public class Test {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3, 4);
Optional<Integer> optional = stream.reduce(Integer::sum);
Integer reduce = optional.get();
System.out.println("reduce = " + reduce); // reduce = 10
}
}
- 示例:
package top.open1024.stream.demo24;
import java.util.Optional;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 10:49
*/
public class Test {
public static void main(String[] args) {
// 求最大值
Optional<Integer> optional = Stream.of(-1, -10, 3, 5, 9).reduce(Integer::max);
Integer reduce = optional.get();
System.out.println("reduce = " + reduce); // reduce = 9
}
}
3.5.9 collect
- 收集流所操作的元素并将其转换为其他形式:
<R, A> R collect(Collector<? super T, A, R> collector);
- 示例:
package top.open1024.stream.demo21;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 10:37
*/
public class Test {
public static void main(String[] args) {
List<Integer> collect = Stream.of(1, 1, 2, 1, 3, 4).distinct().collect(Collectors.toList());
System.out.println("collect = " + collect); // collect = [1, 2, 3, 4]
}
}
3.5.10 所有终止操作的方法列表
方法 | 描述 |
---|---|
boolean****allMatch(Predicate p) | 检查是否匹配所有元素 |
boolean****anyMatch(Predicate p) | 检查是否至少匹配一个元素 |
boolean****noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
Optional<T> findFirst() | 返回第一个元素 |
Optional<T> findAny() | 返回当前流中的任意元素 |
long****count() | 返回流中元素总数 |
Optional<T> max(Comparator c) | 返回流中最大值 |
Optional<T> min(Comparator c) | 返回流中最小值 |
void****forEach(Consumer c) | 迭代 |
T****reduce(T iden, BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回 T |
U****reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回 Optional |
R****collect(Collector c) | 将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法 |
-
Collector接口中方法的实现决定了如何对流执行收集的操作(如收集到 List、Set、Map)。
-
另外, Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例。
4 Optional类
4.1 概述
-
到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见的原因。以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查null值的方式来防止代码污染,它鼓励程序员写干净的代码。受到Google的Guava的启发,Optional类已经成为了JDK 8类库的一部分。
-
Optional实际上是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供了很多有用的方法,这样我们就不用显示进行null值检测。
4.2 创建Optional对象
- 创建一个空的(没有元素的)Optional:
public static<T> Optional<T> empty() {}
- 创建一个非空的(有元素的)Optional:
public static <T> Optional<T> of(T value) {}
- 创建一个可能为空的(没有元素的),也可能是非空的(有元素的)Optional:
public static <T> Optional<T> ofNullable(T value) {}
- 示例:
package top.open1024.optional.demo;
import java.util.Optional;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 12:37
*/
public class Test {
public static void main(String[] args) {
// 创建空的Optional
Optional<String> empty = Optional.empty();
System.out.println("empty = " + empty);
}
}
- 示例:
package top.open1024.optional.demo1;
import java.util.Optional;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 12:39
*/
public class Test {
public static void main(String[] args) {
// 创建一个非空的Optional
Optional<String> optional = Optional.of("abc");
System.out.println("optional = " + optional);
}
}
- 示例:
package top.open1024.optional.demo2;
import java.util.Optional;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 12:41
*/
public class Test {
public static void main(String[] args) {
// 创建一个可能为空的,也可能是非空的Optional
Optional<String> optional = Optional.ofNullable("abc");
System.out.println("optional = " + optional); // optional = Optional[abc]
optional = Optional.ofNullable(null);
System.out.println("optional = " + optional); // optional = Optional.empty
}
}
4.3 从Optional容器中获取元素
- 获取元素,
要求Optional容器必须非空
:
public T get() {}
- 如果容器中有元素,就返回容器中的元素;否则,就返回默认值:
public T orElse(T other) {}
- 如果容器中有元素,就返回容器中的元素;否则,就返回Supplier接口的Lambda表达式提供的值:
public T orElseGet(Supplier<? extends T> other) {}
- 如果容器中有元素,就返回容器中的元素;否则,就抛出指定的异常:
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {}
- 示例:
package top.open1024.optional.demo3;
import java.util.Optional;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 12:50
*/
public class Test {
public static void main(String[] args) {
Optional<String> optional = Optional.ofNullable("abc");
String s = optional.get();
System.out.println("s = " + s);
}
}
- 示例:
package top.open1024.optional.demo4;
import java.util.Optional;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 12:53
*/
public class Test {
public static void main(String[] args) {
String str = "abc";
// Optional容器中有元素
Optional<String> optional = Optional.ofNullable(str);
String s = optional.orElse("bcd");
System.out.println("s = " + s); // s = abc
str = null;
// Optional容器中没有元素
Optional<String> optional2 = Optional.ofNullable(str);
s = optional2.orElse("bcd");
System.out.println("s = " + s); // s = bcd
}
}
- 示例:
package top.open1024.optional.demo5;
import java.util.Optional;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 12:59
*/
public class Test {
public static void main(String[] args) {
String str = "abc";
// Optional容器有元素
Optional<String> optional = Optional.ofNullable(str);
String s = optional.orElseGet(String::new);
System.out.println("s = " + s); // s = abc
// Optional容器没有元素
str = null;
Optional<String> optional2 = Optional.ofNullable(str);
s = optional2.orElseGet(String::new);
System.out.println("s = " + s); // s =
}
}
- 示例:
package top.open1024.optional.demo6;
import java.util.Optional;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 13:03
*/
public class Test {
public static void main(String[] args) {
String str = "abc";
// Optional容器中有元素
Optional<String> optional = Optional.ofNullable(str);
String s = optional.orElseThrow(() -> new RuntimeException("str不能为null"));
System.out.println("s = " + s); // s = abc
// Optional容器中没有元素
str = null;
Optional<String> optional2 = Optional.ofNullable(str);
s = optional2.orElseThrow(() -> new RuntimeException("str不能为null"));
System.out.println("s = " + s); // Exception in thread "main" java.lang.RuntimeException: str不能为null
}
}
4.3 Optional的判断方法
- 判断Optional容器中是否有元素:
public boolean isPresent() {}
- 判断Optional容器中是否有元素,如果有,则对它进行Consumer指定的操作;否则,啥也不做。
public void ifPresent(Consumer<? super T> consumer) {}
- 判断Optional容器中是否有元素,如果有,则对它进行Function接口指定的操作;否则,啥也不做。
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {}
- 示例:
package top.open1024.optional.demo7;
import java.util.Optional;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 13:13
*/
public class Test {
public static void main(String[] args) {
String str = "abc";
Optional<String> optional = Optional.ofNullable(str);
boolean present = optional.isPresent();
System.out.println("present = " + present); // present = true
str = null;
Optional<String> optional2 = Optional.ofNullable(str);
boolean present2 = optional2.isPresent();
System.out.println("present2 = " + present2); // present2 = false
}
}
- 示例:
package top.open1024.optional.demo8;
import java.util.Optional;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 13:13
*/
public class Test {
public static void main(String[] args) {
String str = "abc";
Optional<String> optional = Optional.ofNullable(str);
optional.ifPresent(System.out::println); // abc
str = null;
Optional<String> optional2 = Optional.ofNullable(str);
optional2.ifPresent(System.out::println);
}
}
- 示例:
package top.open1024.optional.demo9;
import java.util.Optional;
/**
* @author open1024
* @version 1.0
* @since 2021-10-10 13:13
*/
public class Test {
public static void main(String[] args) {
String str = "abc";
Optional<String> optional = Optional.ofNullable(str);
optional = optional.map(String::toUpperCase);
System.out.println("optional = " + optional); // optional = Optional[ABC]
str = null;
Optional<String> optional2 = Optional.ofNullable(str);
optional2 = optional2.map(String::toUpperCase);
System.out.println("optional2 = " + optional2); // optional2 = Optional.empty
}
}
评论区