Optional类
到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见原因。以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到Google Guava的启发,Optional类已经成为Java 8类库的一部分。
Optional实际上是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
1 API
1.1 创建Optional对象
(1)static Optional empty() :用来创建一个空的Optional
@Test public void test01(){ Optional<String> opt = Optional.empty(); System.out.println(opt); }
(2)static Optional of(T value) :用来创建一个非空的Optional
@Test public void test02(){ String str = "hello"; Optional<String> opt = Optional.of(str); System.out.println(opt); }
(3)static Optional ofNullable(T value) :用来创建一个可能是空,也可能非空的Optional
//一般用这一种创建
@Test public void test03(){ String str = null; Optional<String> opt = Optional.ofNullable(str); System.out.println(opt); }
1.2 从Optional容器中取出所包装的对象
(1)T get() :要求Optional容器必须非空
@Test public void test04(){ String str = "hello"; Optional<String> opt = Optional.of(str); System.out.println(opt.get()); }
(2)T orElse(T other) :
用的最多
orElse(T other) 与ofNullable(T value)配合使用,
如果Optional容器中非空,就返回所包装值,如果为空,就用orElse(T other), other是指定的默认值(备胎)代替
@Test public void test05(){ String str = "涤魂圣枪"; Optional<String> opt = Optional.ofNullable(str); String string = opt.orElse("圣枪游侠"); System.out.println(string); }
(3)T orElseGet(Supplier<? extends T> other) :
如果Optional容器中非空,就返回所包装值,如果为空,就用Supplier接口的Lambda表达式提供的值代替
@Test public void test06(){ Optional<String> optional = Optional.ofNullable("涤魂圣枪"); String s = optional.orElseGet(() -> "圣枪游侠"); // String s = optional.orElseGet(() -> new String("圣枪游侠"));供给型接口 System.out.println(s); }
(4) T orElseThrow(Supplier<? extends X> exceptionSupplier)
如果Optional容器中非空,就返回所包装值,如果为空,就抛出你指定的异常类型代替原来的NoSuchElementException
@Test public void test07(){ String str = null; Optional<String> opt = Optional.ofNullable(str); String string = opt.orElseThrow(()->new RuntimeException("optional值为空")); System.out.println(string); }
3、其他方法
(1)boolean isPresent() :判断Optional容器中是否有值
@Test public void test08(){ Optional<String> op = Optional.of("hello"); boolean present = op.isPresent(); System.out.println(present); }
(2)void ifPresent(Consumer<? super T> consumer) :
判断Optional容器中的值是否存在,如果存在,就对它进行Consumer指定的操作,如果不存在就不做
@Test public void test09(){ Optional<String> op = Optional.of("hello"); op.ifPresent(s -> System.out.println("存在值")); }
(3) Optional map(Function<? super T,? extends U> mapper)
判断Optional容器中的值是否存在,如果存在,就对它进行Function接口指定的操作,如果不存在就不做
@Test public void test10(){ String str = "Hello"; Optional<String> opt = Optional.ofNullable(str); //判断是否是纯字母单词,如果是,转为大写,否则保持不变 String result = opt.filter(s->s.matches("[a-zA-Z]+")). map(s -> s.toLowerCase()). orElse(str); System.out.println(result); }
2 练习
2.1 练习1
案例:
(1)声明一个Girl类型,包含姓名(String)属性
(2)声明一个Boy类型,包含姓名(String),女朋友(Girl)属性
(3)在测试类中,创建一个Boy对象,并
如果他有女朋友,显示他女朋友名称;
如果他没有女朋友,他的女朋友默认为“嫦娥”,即只能欣赏“嫦娥”了
class Girl{ private String name; public Girl(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Girl [name=" + name + "]"; } } class Boy{ private String name; private Girl girlFriend; public Boy(String name, Girl girlFriend) { super(); this.name = name; this.girlFriend = girlFriend; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Girl getGirlFriend() { return girlFriend; } public void setGirlFriend(Girl girlFriend) { this.girlFriend = girlFriend; } @Override public String toString() { return "Boy [name=" + name + ", girlFriend=" + girlFriend + "]"; } }
测试类
public static void main(String[] args) { // Boy boy = new Boy("张三",null); Boy boy = new Boy("张三",new Girl("翠翠")); Optional<Girl> grilFriend = Optional.ofNullable(boy.getGirlFriend()); Optional.of(grilFriend.orElse(new Girl("嫦娥"))).ifPresent(g->System.out.println(g)); }
2.2 练习2
案例:
(1)声明学生类,包含姓名和年龄
(2)添加几个学生对象到一个ArrayList集合中
(3)对集合中的学生进行操作,找出年龄大于30岁的,并取出第一个学生,如果没有这样的学生,用无参构造new一个学生对象,打印学生信息
学生类示例代码:
class Student{ private String name; private int age; public Student(String name, int age) { super(); this.name = name; this.age = age; } public Student() { super(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } }
测试类
@Test public void test1(){ ArrayList<Student> list = new ArrayList<>(); list.add(new Student("张三", 23)); //... //取出流中第一个年龄大于30岁的学生的年龄,并打印它的年龄,如果没有,用无参构造创建一个学生对象 Student stu = list.stream() .filter(s -> s.getAge()>30) .findFirst().orElse(new Student()); System.out.println("学生的年龄:" + stu.getAge()); }