菜鸟为了巩固所写
目录
有不少 Stream API 函数直接 返回 Optional 对象,以下是一个示例:
一、概述
1、讨厌的NullPointerException
- 由于Stream API 中经常需要“级联”多个操作,因此,如果中间某个操作遇到 null 引用时,如何处理它是个麻烦事。
- 默认情况下,如果针对null 引用调用某个类的实例方法, JVM 会抛出NullPointerException ,如果不做妥善处理 ,这个异常可能 会“打断”流处理管线。
- 为了解决这个问题,Java 8 专门 引入了一个 Optional<T> 类。
2、Optional类型简介
- Optional对象是一个“可能为 null的对象。
- 所有那些有可能返回一个null 引用的操作,都应该返回一个 Optional 对象。
- Optional对象定义了一个isPresent 方法用于确定它是否包容一个有效的值。如果值有效,可以调用它的 get 方法提取出这个值。
- 如果isPresent() 返回 false ,代码又尝试调用它的 get() 方法,JVM 会抛出一个 NoSuchElementException 。
二、使用Optional
1、构建Optional实例
综合示例1
package com.jinxuliang;
import java.util.Optional;
import java.util.stream.Stream;
public class CreateOptionalDemo {
public static void main(String[] args) {
Stream<String> stream = Stream.of("Optional", "type", null, "", "is", "very", "useful");
stream.map(str -> processString(str, 2)) //截取两个字符
.filter(str -> str.isPresent()) //过滤掉空引用
.forEach(System.out::println); //输出结果
}
//截取指定长度的字符串
public static Optional<String> processString(String string, int length) {
if (string == null || length <= 0 || string.length() < length) {
return Optional.empty();
}
//构建Optional对象
return Optional.of(string.substring(0, length));
}
}
最简单的构建Optional 对象的方法是使用其 of() 方法,另一个empty() 方法用于构建一个 “空的 Optional 对象。
示例1
//截取指定长度的字符串
public static Optional<String> processString(String string, int length) {
if (string == null || length <= 0 || string.length() < length) {
return Optional.empty();
}
//构建Optional对象
return Optional.of(string.substring(0, length));
}
另一个有用的方法是Optional.ofNullable(obj) 。当obj==null 时,此方法返回 Optional.empty() ,否则返回 Optional.Of(obj) 。
使用Optional。示例2
返回Optional 对象的函数,可以直接用于 map 函数中:
public static void main(String[] args) {
Stream<String> stream = Stream.of("Optional", "type", null, "", "is", "very", "useful");
stream.map(str -> processString(str, 2)) //截取两个字符
.filter(str -> str.isPresent()) //过滤掉空引用
.forEach(System.out::println); //输出结果
}
有不少 Stream API 函数直接 返回 Optional 对象,以下是一个示例:
package com.jinxuliang;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
public class UseOptional {
public static void main(String[] args) {
List<Integer> numbers = List.of(106, 234, 39, 134, 19, 80);
//min函数(还有max函数),返回Optional
var result = numbers.stream()
.min(Comparator.naturalOrder());
System.out.println(result.get());//19
//of函数返回Optional
Optional<String> str = Optional.of("Hello");
//isPresent()可以简写为ifPresent
str.ifPresent(System.out::println);
//map函数返回Optional
var stringLength= str.map(String::length);
stringLength.ifPresent(System.out::println);
}
}
三、针对原始数据的Optional
一般来说,只有引用类型才有null 值,原始数据类型的变量,比如 int ,一定义就有值了,不会出现 null 情况。
但原始数据类型的包装类,比如Integer ,使用它们定义的变量,则是有可能为 null 的。为此, JDK 中为它们提供了专门的 Optional 类型 OptionalInt 、 OptionalDouble 和OptionalLong 以 避免发生不必要的装箱和拆箱操作。
1、OptionalInt
针对原始数据类型,JDK 提供了 OptionalInt, OptionalLong 和OptionalDouble 三个类,拥有 getAsXXX() 的方法,下面以 OptionalInt 为例介绍其用法:
package com.jinxuliang.model;
public class OrderClient {
private int id;
private String name;
private String address;
public OrderClient(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
@Override
public String toString() {
return "OrderClient{" +
"id=" + id +
", name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
package com.jinxuliang;
import com.jinxuliang.model.OrderClient;
import java.util.Comparator;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class OptionalIntTest {
public static void main(String[] args) {
// 创建一个“空的”OptionalInt实例
OptionalInt empty = OptionalInt.empty();
// 创建一个 OptionalInt实例,保存数值287
OptionalInt number = OptionalInt.of(287);
//从OptionaInt实例中提取数据的方法
if (number.isPresent()) {
int value = number.getAsInt();
System.out.println("Number is " + value);
} else {
System.out.println("Number is absent.");
}
// 一些Stream API方法,返回OptionalInt
OptionalInt numbers = IntStream.of(1, 10, 37, 20, 31)
.filter(n -> n % 2 == 1).max();
if (numbers.isPresent()) {
int value = numbers.getAsInt();
System.out.println("最大值为: " + value);
} else {
System.out.println("流为空");
}
var client = getOrderClient();
//client有可能为null,使用orElse指定默认值
String name = client.map(OrderClient::getName).orElse("无名氏");
System.out.println(name);
}
//用Optional封装有可能为null值的方法
private static Optional<OrderClient> getOrderClient() {
var ranValue = new Random().nextInt(100);
if (ranValue % 2 == 0) {
return Optional.empty();
} else {
var client = new OrderClient(ranValue,
"client" + ranValue);
return Optional.of(client);
}
}
}
四、类型转换
Optional类中定义有一个 map 方法,可以对结果进行类型 转换,得到 另一个 Optional 对象:
package com.jinxuliang;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
public class UseOptional {
public static void main(String[] args) {
List<Integer> numbers = List.of(106, 234, 39, 134, 19, 80);
//min函数(还有max函数),返回Optional
var result = numbers.stream()
.min(Comparator.naturalOrder());
System.out.println(result.get());//19
//of函数返回Optional
Optional<String> str = Optional.of("Hello");
//isPresent()可以简写为ifPresent
str.ifPresent(System.out::println);
//map函数返回Optional
var stringLength= str.map(String::length);
stringLength.ifPresent(System.out::println);
}
}