IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android Optional使用 -> 正文阅读

[移动开发]Android Optional使用

1.Optional
Optional是Java8提供的为了解决null安全问题的一个API。善用Optional可以使代码中很多繁琐、丑陋的设计变得十分优雅。
java8之所以要提出这个对象,是因为java8中主要引入了lambda表达式,这种函数式编程中大量的链式调用,如果用原始的方法去判断nullpointException,会破坏lambda这种风格。

比如在Android开发中,接口json中,对象里面有对象,对象中有属性。每次使用或作为参数传参时,都要!=null非空判断。一个还好,当属性嵌套得非常深的时候,就会出现以下代码。
public class Person {
private int age;
private String name;
private Address address;

public Person(int age, String name, Address address) {
this.age = age;
this.name = name;
this.address = address;
}

//…省略set、get方法

public static class Address {
private String roomNum;
private String areaNum;
public Address(String roomNum, String areaNum) {
this.roomNum = roomNum;
this.areaNum = areaNum;
}
//…省略set、get方法
}
}

//错误码
String errorNum = “error”;
if (barry.getAddress() != null
&& barry.getAddress().getAreaNum() != null
&& !barry.getAddress().getAreaNum().equals(errorNum)) {
String areaNum = barry.getAddress().getAreaNum();
//最后使用areaNum属性做事情
System.out.println("areaNum = " + areaNum);
}
总之,就是不好看,臃肿,也不优雅。

Java8中,为了解决以上问题,引入了Optional类。Optional是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

2.Optional中的方法
①创建Optional
Optional有三个静态构造方法:
(1) Optional.of(T value)
public static < T> Optional< T> of(T value) {
return new Optional<>(value);
}
该方法通过一个非 null 的 value 来构造一个 Optional,返回的 Optional 包含了 value 这个值。对于该方法,传入的参数一定不能为 null,否则便会抛出 NullPointerException。

举例:
Optional< String> op1 = Optional.of(“Hello”);
System.out.println(op1.isPresent()); // 输出 true
System.out.println(op1.get()); // 输出 Hello
Optional< String> op2 = Optional.of(null); // 抛出异常

(2) Optional.ofNullable(T value)
public static < T> Optional< T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
该方法和 of 方法的区别在于,传入的参数可以为 null 。从源码内部可以看出,该方法会判断传入的参数是否为 null,如果为 null 的话,返回的就是 Optional.empty()。

举例:
Optional< String> op2 = Optional.ofNullable(null);
System.out.println(op2.isPresent()); // 输出 false

(3) Optional.empty()
public static< T> Optional< T> empty() {
@SuppressWarnings(“unchecked”)
Optional< T> t = (Optional< T>) EMPTY;
return t;
}
该方法用来构造一个空的 Optional,即该 Optional 中不包含值 。其实底层实现还是 如果 Optional 中的 value 为 null ,则该 Optional 为不包含值的状态,然后在 API 层面将 Optional 表现的不能包含 null值,使得 Optional 只存在 包含值 和 不包含值 两种状态。

②isPresent()
判断Optional中包裹的值,如果不为null,返回true,为null返回false。

举例:
(1) Optional< Object> optional = Optional.ofNullable(null);
if (optional.isPresent()) {
Object value = optional.get();
//做操作
System.out.println(value);
}

(2)ifPresent() 如果实例非空,调用 Comsumer Lambda 表达式:
Optional< String> op1 = Optional.of(“Hello”);
op1.ifPresent((s) -> {
System.out.println(s); // 输出 Hello
});

③Optional.get()
获取Optional中包裹的值,如果值为null,抛出NoSuchElementException异常,一般会配合isPresent()进行判断后,再使用get获得值

举例:
(1)Optional< String> op1 = Optional.of(“Hello”);
System.out.println(op1.isPresent()); // 输出 true
System.out.println(op1.get()); // 输出 Hello
(2)Optional< String> optional = Optional.ofNullable(“wally”);
if (optional.isPresent()) {
String value = optional.get();
//做操作…
}

④orElse
判断Optional中包裹的值,如果值为null,返回orElse()中传入的默认值。

举例:
Optional< String> op1 = Optional.of(“Hello”);
System.out.println(op1.orElse(“World”)); // 输出 Hello
Optional< String> op2 = Optional.ofNullable(null);
System.out.println(op2.orElse(“World”)); // 输出 World

⑤orElseGet(Supplier<? extends T> other)
如果实例非空,返回该实例,否则返回 Supplier

举例:
Optional< String> op1 = Optional.of(“Hello”);
System.out.println(op1.orElseGet(() -> {return new String(“World”);})); // 输出 Hello
Optional< String> op2 = Optional.ofNullable(null);
System.out.println(op2.orElseGet(() -> {return new String(“World”);})); // 输出 World

⑥orElseThrow()
判断Optional中包裹的值,如果为null,抛出Supplier接口中get()返回的Throwable异常对象。否则返回Optional中包裹的值。

举例:
try {
//对象方式
Object value = optional.orElseThrow(new Supplier< Throwable>() {
@Override
public Throwable get() {
return new NullPointerException(“value is null”);
}
});
//lambda方式
Object value = optional.orElseThrow((Supplier< Throwable>) () -> new NullPointerException(“value is null”));
//输出
System.out.println("value: " + value);
} catch (Throwable throwable) {
throwable.printStackTrace();
}

⑦map(Function f)
判断Optional中包裹的值,如果不为null,调用Function接口的apply()方法,获得新值,生成新的一个Optional并包裹新值。如果为null,则返回一个null值的Optional。

举例:
Optional< String> newOptional = Optional.of(“hello”).map(new Function<Object, String>() {
@Override
public String apply(Object o) {
return “hi”;
}
});
if (newOptional.isPresent()) {
String value = newOptional.get();
System.out.println(value);
}

⑧flatMap(Function mapper)
flatMap和map类似,但是Function接口的apply方法返回的是Optional对象。注意apply方法返回的Optional中包裹的值不能为null,否则抛出NullPointerException异常。

举例:
Optional< String> optional = Optional.of(“oh no”).flatMap(new Function<String, Optional< String>>() {
@Override
public Optional< String> apply(String s) {
return Optional.of(“oh shit”);
}
});
optional.ifPresent(System.out::println);

⑨filter
对Optional中包裹的值,做过滤操作,调用Predicate中的test方法,做过滤操作判断,如果返回true,返回原始的Optional,否则返回一个null值的Optional。配合ifPresent()判断,过滤成功则不会调用输出方法。

举例:
Optional< String> stringOptional = Optional.of(“wally”).filter(new Predicate< String>() {
@Override
public boolean test(String value) {
return value.length() > 3;
}
});
stringOptional.ifPresent(System.out::println);

3.Optional的使用
一般,我们判断对象null的代码如下:
public static String getName(User u) {
if (u == null)
return “Unknown”;
return u.name;
}
有了optional后,我们千万不要改写成下面这种方式:
public static String getName(User u) {
Optional< User> user = Optional.ofNullable(u);
if (!user.isPresent())
return “Unknown”;
return user.get().name;
}

这样改写非但不简洁,而且其操作还是和第一段代码一样。无非就是用isPresent方法来替代u==null。这样的改写并不是Optional正确的用法,我们再来改写一次。
public static String getName(User u) {
return Optional.ofNullable(u)
.map(user->user.name)
.orElse(“Unknown”);
}
这样才是正确使用Optional的姿势。那么按照这种思路,我们可以安心的进行链式调用,而不是一层层判断了。

注意:要使用Optional,必须将所有属性都用Optional包一次,所以文章开头我们的Person类的Model就要改一下:
public class PersonWithOptional {
private Optional< Integer> age;
private Optional< String> name;
private Optional< Address> address;

public PersonWithOptional(Optional< Integer> age, Optional< String> name, Optional< Address> address) {
this.age = age;
this.name = name;
this.address = address;
}

public static class Address {
private Optional< String> roomNum;
private Optional< String> areaNum;
public Address(Optional< String> roomNum, Optional< String> areaNum) {
this.roomNum = roomNum;
this.areaNum = areaNum;
}
//…省略set、get方法
}
//…省略set、get方法
}

Optional.of(barry).flatMap(new Function<PersonWithOptional, Optional<PersonWithOptional.Address>>() {
@Override
public Optional<PersonWithOptional.Address> apply(PersonWithOptional person) {
//取出Address属性对象
return barry.getAddress();
}
}).flatMap(new Function<PersonWithOptional.Address, Optional< String>>() {
@Override
public Optional< String> apply(PersonWithOptional.Address address) {
//取出Address属性对象中的areaNum属性
return address.getAreaNum();
}
}).filter(new Predicate< String>() {
@Override
public boolean test(String areaNum) {
//校验areaNum的合法性,不合法在下面的ifPresent时被抛弃掉
return !areaNum.equals(errorNum);
}
}).ifPresent(new Consumer< String>() {
@Override
public void accept(String areaNum) {
//最后使用areaNum属性做事情
System.out.println("areaNum = " + areaNum);
}
});
可能有人会说,你这不是纯属增加代码量吗,这比传统写法写多好多代码呀!对于这种情况,终究还是那句话,代码是人看的,代码太复杂不利于阅读,尤其是那种写完几个星期后,只有上帝才知道是什么的代码~况且我们还有lambda这个大杀器!
使用lambda,省略了内部类,是不是代码量少了,也依然结构清晰~
Optional.of(barry)
.flatMap(person -> barry.getAddress())
.flatMap(PersonWithOptional.Address::getAreaNum)
.filter(areaNum -> !areaNum.equals(errorNum))
.ifPresent(areaNum -> System.out.println("areaNum = " + areaNum));

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-02-16 13:14:01  更:2022-02-16 13:14:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 14:41:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码