JAVA8新特性Optional,⾮空判断
Optional
java 的 NPE(Null Pointer Exception)所谓的空指针异常搞的头昏脑涨, 有⼤佬说过 “防⽌ NPE,是程序员的基本修养。” 但是修养归修养,也是我们程序员最头疼的问题之⼀,那么我们今天就要尽可能的利⽤Java8的新特性Optional来尽量简化代码同时⾼效处理 NPE(Null Pointer Exception 空指针异常)
认识Optional并简单使⽤
简单来说,Opitonal 类就是 Java 提供的为了解决⼤家平时判断对象是否为空⽤ 会⽤ null!=obj 这样的⽅式存在的判断,从⽽令⼈头疼导致 NPE(Null Pointer Exception 空指针异常),同时 Optional 的存在可以让代码更加简单,可读性跟⾼,代码写起来更⾼效.
正常代码,判断对象是否为空
Admin person=new Admin();
if (null==admin){
return "admin为null";
}
return person;
当我们使⽤Optional判断对象是否为空时:
//⼀、Optional判断对象是否为空
Admin admin = new Admin();
Optional<Admin> admin1 = Optional.ofNullable(admin);
神奇的Optional类
Optional类内部
⾸先我们先打开 Optional 的内部, 去⼀探究竟 先把⼏个创建 Optional 对象的⽅法提取出来:
【这些⽅法很重要⼀定要看懂哦,后⾯都会使⽤到的】
public final class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
//我们可以看到两个构造⽅格都是private 私有的
//说明我们没办法在外⾯去new出来Optional对象
private Optional() {
this.value = null;
}
private Optional(T value) {
this.value = quireNonNull(value);
}
//这个静态⽅法⼤致是创建出⼀个包装值为空的⼀个对象因为没有任何参数赋值
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
//这个静态⽅法⼤致是创建出⼀个包装值⾮空的⼀个对象因为做了赋值
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
//这个静态⽅法⼤致是如果参数value为空,则创建空对象,如果不为空,则创建有参对象
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
}
再做⼀个简单的实例展⽰ 与上⾯对应:
// 1、创建⼀个包装对象值为空的Optional对象
Optional<String> optEmpty = pty();
// 2、创建包装对象值⾮空的Optional对象(使⽤of⽅法⼀定要保证对象⾮空,否则会抛异常)
Optional<String> optOf = Optional.of("optional");
// 3、创建包装对象值允许为空也可以不为空的Optional对象
Optional<String> optOfNullable1 = Optional.ofNullable(null);
Optional<String> optOfNullable2 = Optional.ofNullable("optional");
我们关于创建 Optional 对象的内部⽅法⼤致分析完毕 接下来也正式的进⼊ Optional 的学习与使⽤中。
Optional类常⽤的⽅法
<() ⽅法【返回对象的值】
get()⽅法源码:
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
由此我们可以看到get()⽅法返回的是⼀个Optional实例值,
也就是说,源码中如果value的值不为空就会返回value,如果为空,则会直接抛出⼀个异常 "No value present"
测试实例代码:
Admin newAdmin = new Admin();
newAdmin.setName("get⽅法获取对象值");
Admin Nadmin = Optional.ofNullable(newAdmin).get();
返回数据:
Nadmin=Admin(id=null, loginName=null, password=null, email=null, name=get⽅法获取对象值, mobile=null, departmentId=null, registerDate=null, l astLoginDate=null, status=null, delFlag=null)
Optional.isPresent()⽅法【判读是否为空】
isPresent()⽅法源码:
public Boolean isPresent() {
return value != null;
}
从源码上我们可以看到 isPresent⽅法返回的是⼀个true/false值,如果判断的对象不为空着返回false,为空着返回true
测试实例代码:
Admin admin3 = new Admin();
admin3.setName("isPresent⽅法判断是否为空");
boolean present = Optional.ofNullable(admin3).isPresent();
注意:null空对象返回false
public static void main(String[] args) {
String  a ="";
String  b  = null;
User2 c = new User2();
List<String> d = new ArrayList<>();
List<User2> e = new ArrayList<>();
System.out.println("String空字符串:" + Optional.ofNullable(a).isPresent());
System.out.println("null: " + Optional.ofNullable(b).isPresent());
System.out.println("空集合泛型String :" + Optional.ofNullable(d).isPresent());
System.out.println("空集合泛型对象:" + Optional.ofNullable(e).isPresent());
// 输出结果:
/**
*  String空字符串:true
*  null: false
*  空集合泛型String :true
*  空集合泛型对象:true
*/
}
ifPresent() ⽅法
如果Optional实例有值则为其调⽤consumer,否则不做处理
ifPresent⽅法,⾸先需要了解Consumer类。简答地说,Consumer类包含⼀个抽象⽅法。该抽象⽅法对传⼊的值进⾏处理,但没有返回值。
Java8⽀持不⽤接⼝直接通过lambda表达式传⼊参数。如果Optional实例有值,调⽤ifPresent()可以接受接⼝段或lambda表达式。类似下⾯的代码://ifPresent⽅法接受lambda表达式作为参数。
//lambda表达式对Optional的值调⽤consumer进⾏处理。
Optional<User1> user = Optional.ofNullable(user1);
user .ifPresent((value) -> {
System.out.println("user : " + value);
return “adf”;//此处不可以有返回值
});
Optional.filter() ⽅法【过滤对象】
filter() ⽅法源码展⽰:
public Optional<T> filter(Predicate<? super T> predicate) {
//如果为空直接返回this
if (!isPresent())
return this; else
/
/判断返回本⾝还是空Optional
st(value) ? this : empty();
}
接受⼀个对象,然后对他进⾏条件过滤,如果条件符合则返回 Optional 对象本⾝,如果不符合则返回空 Optional
测试代码实例:
Admin admin4 = new Admin();
admin4.setName("filter⽅法,根据条件过滤对象");
Optional<Admin> adminfilter = Optional.ofNullable(admin4).filter(p -> p.getName().equals("filter⽅法,根据条件过滤对象"));
Optional.map() ⽅法 [对象进⾏⼆次包装]
map() ⽅法将对应 Funcation 函数式接⼝中的对象,进⾏⼆次运算,封装成新的对象然后返回在 Optio
nal 中 源码:
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
//如果为空返回⾃⼰
if (!isPresent())
return empty();
else {
//否则返回⽤⽅法修饰过的Optional
return Optional.ofNullable(mapper.apply(value));
}
}
测试代码⽤例:
Admin admin5 = new Admin();
Optional<String>  adminFlatMap= Optional.ofNullable(admin5).map(m -> Optional.Name()).orElse("name为空"));
如果包装对象为空的话,就执⾏ orElse ⽅法⾥的 value,如果⾮空,则返回写⼊对象 源码:
public T orElse(T other) {
//如果⾮空,返回value,如果为空,返回other
return value != null ? value : other;
}
这个与 orElse 很相似,⼊参不⼀样,⼊参为 Supplier 对象,为空返回传⼊对象的. get() ⽅法,如果⾮空则返回当前对象 源码:
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : ();
}
测试代码实例:
Optional<Supplier<Person>> sup=Optional.ofNullable(Person::new);
//调⽤get()⽅法,此时才会调⽤对象的构造⽅法,即获得到真正对象
Optional.ofNullable(person).());
Supplier 对象:
Supplier 也是创建对象的⼀种⽅式, 简单来说,Suppiler 是⼀个接⼝,是类似 Spring 的懒加载,声明之后并不会占⽤内存,只有执⾏了 get() ⽅法之后,才会调⽤构造⽅法创建出对象创建对象的语法的话
就是
语法:Supplier supPerson= Person::new
需要使⽤时()即可
如果对象为空,就抛出⾃定义的异常,如果不为空则返回当前对象,⽅便异常的处理:
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
();
}
}
测试代码⽤例:
//简单的⼀个查询
Member member = memberService.Phone());
Optional.ofNullable(member).orElseThrow(() -> new ServiceException("没有查询的相关数据"));
相似⽅法区别
orElse() 和 orElseGet() 和 orElseThrow() 的异同点
⽅法效果类似,如果对象不为空,则返回对象,如果为空,则返回⽅法体中的对应参数,所以可以看出这三个⽅法体中参数是不⼀样的orElse(T 对象)
orElseGet(Supplier 对象)
orElseThrow(异常)
orEle()
当optional值不存在时,程序执⾏orElse(),返回执⾏后的参数,如果optional值存在时,则orElse()则不会再执⾏。
对于orElse()和orElseGet()⽅法的区别,我们可以通过下⾯optional值得情况可以看出:
optional有值:
import java.util.Arrays;
import java.util.List;
public class orElseOrElseGetComparation {
public static void main(String[] args){
List<Integer> list = Arrays.asList(23,1,3);
int myElse = list.stream().reduce(Integer::sum).orElse(get("myElse"));
int myElseGet = list.stream().reduce(Integer::sum).orElseGet(() -> get("myElseGet"));
System.out.println("myElse的值"+myElse);
System.out.println("myElseGet的值"+myElseGet);
}
public static int get(String name){
System.out.println(name+"执⾏了该⽅法");
return 1;
}
}
结果:
myElse执⾏了该⽅法
myElse的值27
myElseGet的值27
optinoal为空时:
import java.util.Arrays;
import java.util.List;
public class orElseOrElseGetComparation {
public static void main(String[] args){
List<Integer> list = Arrays.asList();
int myElse = list.stream().reduce(Integer::sum).orElse(get("myElse"));
int myElseGet = list.stream().reduce(Integer::sum).orElseGet(() -> get("myElseGet"));
System.out.println("myElse的值"+myElse);
System.out.println("myElseGet的值"+myElseGet);
}
public static int get(String name){
System.out.println(name+"执⾏了该⽅法");
return 1;
}
}
结果:
myElse执⾏了该⽅法
myElseGet执⾏了该⽅法
myElse的值1
myElseGet的值1
从上⾯的执⾏结果我们可以看出orElse()⽅法在不论optional是否有值都会执⾏,在optional为空值的情况下orElse和orElseGet都会执⾏,当optional不为空时,orElseGet不会执⾏map()和flatMap()区别
map
map 把数组流中的每⼀个值,使⽤所提供的函数执⾏⼀遍,⼀⼀对应,得到元素个数相同的数组流。
flatMap
flat是扁平的意思。它把数组流中的每⼀个值,使⽤所提供的函数执⾏⼀遍,⼀⼀对应。得到元素相同的数组流。只不过,⾥⾯的元素也是⼀个⼦数组流。把这些⼦数组合并成⼀个数组以后,元素个数⼤概率会和原数组流的个数不同。
实例
案例:对给定单词列表 ["Hello","World"],你想返回列表["H","e","l","o","W","r","d"]
第⼀种⽅案 map
String[] words = new String[]{"Hello","World"};
filter过滤对象数组List<String[]> a = Arrays.stream(words)
.map(word -> word.split(""))
.distinct()
.collect(toList());
a.forEach(System.out::print);
代码输出为:[Ljava.lang.String;@12edcd21[Ljava.lang.String;@34c45dca
(返回⼀个包含两个String[]的list)
这个实现⽅式是由问题的,传递给map⽅法的lmbda每个单词⽣成了⼀个String[](String列表)。因此,map返回的流实际上是Stream<String[]> 类型的。你真正想要的是
⽤Stream<String>来表⽰⼀个字符串。
下⽅图是上⽅代码stream的运⾏流程

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。