现在不用再被这些事情恶心了,java8引入了一个新的Optional类。Optional类的Javadoc描述如下:这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
其实也不用多说什么,我通过几个例子来整理下Optional类的用法就好了。下面我会贴出Optional类的源码然后给出使用的例子:
- of:为非null的值创建一个Optional。
public static <T> Optional<T> of(T value) { return new Optional<>(value); }
这里有必要看一下Optional类的构造器,下面先贴出源码:
private Optional() { this.value = null; } private Optional(T value) { this.value = Objects.requireNonNull(value); }
这里有一个Objects类,是java7之后引入的。requireNonNull()方法用来验证对象是否为空,如果对象为空,抛出空指针异常。源码如下:
public static <T> T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; }OK,现在来使用Optional的of方法:
/** * @创建时间: 2015年10月30日 * @相关参数: @param args * @功能描述: of方法通过工厂方法创建Optional类。需要注意的是,创建对象时传入的参数不能为null。如果传入参数为null,则抛出NullPointerException 。 */ public static void main(String[] args) { //调用工厂方法创建Optional实例 Optional<String> name = Optional.of("LinkinPark..."); //传入参数为null,抛出NullPointerException. Optional<String> someNull = Optional.of(null); }
- empty:Returns an empty Optional instance。返回一个对象,该对象调用isPresent()方法返回false
private static final Optional<?> EMPTY = new Optional<>(); public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; }
/** * @创建时间: 2015年10月30日 * @相关参数: @param args * @功能描述: empty,直接get()会报错 */ public static void main(String[] args) { Optional<String> name = Optional.empty(); System.out.println(name.isPresent());//输出false System.out.println(name.get());//报错,输出No value present }
- ofNullable:为指定的值创建一个Optional,如果指定的值为null,则返回一个空的Optional。
public static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value); }
/** * @创建时间: 2015年10月30日 * @相关参数: @param args * @功能描述: ofNullable与of方法相似,唯一的区别是可以接受参数为null的情况。 */ public static void main(String[] args) { //下面创建了一个不包含任何值的Optional实例 Optional<String> op = Optional.ofNullable("LinkinPark。。。"); Optional<String> empty = Optional.ofNullable(null); }
- isPresent:如果值存在返回true,否则返回false。
public boolean isPresent() { return value != null; }
/** * @创建时间: 2015年10月30日 * @相关参数: @param args * @功能描述: isPresent方法用来检查Optional实例中是否包含值 */ public static void main(String[] args) { Optional<String> name = Optional.of("LinkinPark"); if (name.isPresent()) { //在Optional实例内调用get()返回已存在的值 System.out.println(name.get());//输出LinkinPark } }
- get:如果Optional有值则将其返回,否则抛出NoSuchElementException。
public T get() { if (value == null) { throw new NoSuchElementException("No value present"); } return value; }
/** * @创建时间: 2015年10月30日 * @相关参数: @param args * @功能描述: get方法用来得到Optional实例中的值 */ public static void main(String[] args) { Optional<String> name = Optional.ofNullable("LinkinPark..."); Optional<?> empty = Optional.ofNullable(null); try { System.out.println(name.get()); //在空的Optional实例上调用get(),抛出NoSuchElementException System.out.println(empty.get()); } catch (NoSuchElementException ex) { System.out.println(ex.getMessage());//输出:No value present } }
- ifPresent:如果Optional实例有值则为其调用consumer,否则不做处理。Consumer类包含一个抽象方法。该抽象方法对传入的值进行处理,但没有返回值。Java8支持不用接口直接通过lambda表达式传入参数。
public void ifPresent(Consumer<? super T> consumer) { if (value != null) consumer.accept(value); }
/** * @创建时间: 2015年10月30日 * @相关参数: @param args * @功能描述: 如果Optional实例有值,调用ifPresent()可以接受接口段或lambda表达式 */ public static void main(String[] args) { Optional<String> name = Optional.ofNullable("LinkinPark..."); name.ifPresent(System.out::println); }
- orElse:如果有值则将其返回,否则返回指定的其它值。
public T orElse(T other) { return value != null ? value : other; }
/** * @创建时间: 2015年10月30日 * @相关参数: @param args * @功能描述: 如果Optional实例有值则将其返回,否则返回orElse方法传入的参数 */ public static void main(String[] args) { Optional<String> name = Optional.ofNullable("LinkinPark..."); Optional<String> empty = Optional.ofNullable(null); //如果值不为null,orElse方法返回Optional实例的值。如果为null,返回传入的消息。 System.out.println(name.orElse("There is some value!"));//输出:LinkinPark System.out.println(empty.orElse("There is no value present!"));//输出:There is no value present! }
- orElseGet:orElseGet与orElse方法类似,区别在于得到的默认值。orElse方法将传入的字符串作为默认值,orElseGet方法可以接受Supplier接口的实现用来生成默认值。
public T orElseGet(Supplier<? extends T> other) { return value != null ? value : other.get(); }
/** * @创建时间: 2015年10月30日 * @相关参数: @param args * @功能描述: orElseGet与orElse方法类似,区别在于orElse传入的是默认值,orElseGet可以接受一个lambda表达式生成默认值。 */ public static void main(String[] args) { Optional<String> name = Optional.ofNullable("LinkinPark..."); Optional<String> empty = Optional.ofNullable(null); System.out.println(name.orElseGet(() -> "Default Value"));//输出:LinkinPark System.out.println(empty.orElseGet(() -> "Default Value"));//输出:Default Value }
- orElseThrow:如果有值则将其返回,否则抛出supplier接口创建的异常。
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { if (value != null) { return value; } else { throw exceptionSupplier.get(); } }
public class Test { /** * @创建时间: 2015年10月30日 * @相关参数: @param args * @功能描述: orElseThrow与orElse方法类似。与返回默认值不同,orElseThrow会抛出lambda表达式或方法生成的异常 */ public static void main(String[] args) { Optional<String> empty = Optional.ofNullable(null); try { empty.orElseThrow(() -> new LinkinException("No value present in the Optional instance")); } catch (Throwable ex) { System.out.println(ex.getMessage());//输出: No value present in the Optional instance } } } @SuppressWarnings("serial") class LinkinException extends RuntimeException { public LinkinException() { super(); } /** * @param message * @param cause * @param enableSuppression * @param writableStackTrace */ public LinkinException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } /** * @param message * @param cause */ public LinkinException(String message, Throwable cause) { super(message, cause); } /** * @param message */ public LinkinException(String message) { super(message); } /** * @param cause */ public LinkinException(Throwable cause) { super(cause); } }
上面的代码没有问题,其中这个自定义异常设计不合理,因为这里的异常信息不会经常变,也就是这个已经被定义成检查Optional类是否是空的异常了,所以重构下:
package com.linkin.maven.mavenTest; import java.util.Optional; public class Test { /** * @创建时间: 2015年10月30日 * @相关参数: @param args * @功能描述: orElseThrow与orElse方法类似。与返回默认值不同,orElseThrow会抛出lambda表达式或方法生成的异常 */ public static void main(String[] args) { Optional<String> empty = Optional.ofNullable(null); try { empty.orElseThrow(LinkinException::new); } catch (Throwable ex) { System.out.println(ex.getMessage());//输出: No value present in the Optional instance } } } @SuppressWarnings("serial") class LinkinException extends RuntimeException { /** * 不带异常信息 */ public LinkinException() { } /** * @param msg * 带异常信息 */ public LinkinException(String msg) { super(msg); } @Override public String getMessage() { return "No value present in the Optional instance"; } }
- map:如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Optional.ofNullable(mapper.apply(value)); } }
/** * @创建时间: 2015年10月30日 * @相关参数: @param args * @功能描述: map方法用来对Optional实例的值执行一系列操作。通过一组实现了Function接口的lambda表达式传入操作。 */ public static void main(String[] args) { Optional<String> name = Optional.ofNullable("LinkinPark..."); //map方法执行传入的lambda表达式参数对Optional实例的值进行修改。为lambda表达式的返回值创建新的Optional实例作为map方法的返回值。 Optional<String> upperName = name.map(String::toUpperCase); System.out.println(upperName.orElse("No value found"));//输出LINKINPARK... }
- flatMap:如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional。flatMap与map(Funtion)方法类似,区别在于flatMap中的mapper返回值必须是Optional。调用结束时,flatMap不会对结果用Optional封装。
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Objects.requireNonNull(mapper.apply(value)); } }
/** * @创建时间: 2015年10月30日 * @相关参数: @param args * @功能描述: flatMap方法与map方法类似,区别在于mapping函数的返回值不同。map方法的mapping函数返回值可以是任何类型T,而flatMap方法的mapping函数必须是Optional。 */ public static void main(String[] args) { Optional<String> name = Optional.ofNullable("LinkinPark..."); //flatMap与map(Function)非常类似,区别在于传入方法的lambda表达式的返回类型。map方法中的lambda表达式返回值可以是任意类型,在map函数返回之前会包装为Optional。 //但flatMap方法中的lambda表达式返回值必须是Optionl实例。 Optional<String> upperName = name.flatMap((value) -> Optional.of(value.toUpperCase())); System.out.println(upperName.orElse("No value found"));//输出LINKINPARK... }
- filter:通过传入限定条件对Optional实例的值进行过滤。如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional。
public Optional<T> filter(Predicate<? super T> predicate) { Objects.requireNonNull(predicate); if (!isPresent()) return this; else return predicate.test(value) ? this : empty(); }
/** * @创建时间: 2015年10月30日 * @相关参数: @param args * @功能描述: 对于filter函数我们应该传入实现了Predicate接口的lambda表达式 */ public static void main(String[] args) { Optional<String> name = Optional.ofNullable("LinkinPark..."); //filter方法检查给定的Option值是否满足某些条件。如果满足则返回同一个Option实例,否则返回空Optional。 Optional<String> longName = name.filter((value) -> value.length() > 6); System.out.println(longName.orElse("The name is less than 6 characters"));//输出LinkinPark... //另一个例子是Optional值不满足filter指定的条件。 Optional<String> anotherName = Optional.of("Linkin"); Optional<String> shortName = anotherName.filter((value) -> value.length() > 6); //输出:name长度不足6字符 System.out.println(shortName.orElse("The name is less than 6 characters"));//输出The name is less than 6 characters }
总结:
高效使用Optional的关键在于,使用一个或者接受正确值,或者返回另一个替代品的方法。
1,ofNullable()方法被设计为null值和可选值之间的一座桥梁,所以我一般使用这个,不怎么用of()。
2,在对Optional对象调用get()方法前,总是应该确认该对象包含值。
3,filter(),map(),flatMap()方法返回的都是一个经过函数式接口处理过的Optional对象,所以可以链式调用。下面给出一个例子:
/** * @创建时间: 2015年10月30日 * @相关参数: @param args * @功能描述: map(),flatMap(),filter()方法的链式调用 */ public static void main(String[] args) { Optional<String> name = Optional.ofNullable("LinkinPark..."); Optional<String> upperName = name.flatMap((value) -> Optional.of(value.toUpperCase())); Optional<String> lowerCase = name.flatMap((value) -> Optional.of(value.toUpperCase())).map(String::toLowerCase); Optional<String> lowerCase1 = name.flatMap((value) -> Optional.of(value.toUpperCase())).map(String::toLowerCase).filter((value) -> value.startsWith("Linkin")); System.out.println(upperName.orElse("No value found"));//输出LINKINPARK... System.out.println(lowerCase.get());//输出linkinpark... System.out.println(lowerCase1.orElse("No value found"));//No value found }