1.7. Optional类型
容器对象,可能包含或不包含非空值。如果存在一个值,isPresent()将返回true,get()将返回值。还提供了依赖于包含值是否存在的附加方法,如orElse()(如果值不存在则返回一个默认值)以及ifPresent()(如果该值存在,则执行一个代码块)。
1.7.1. 如何使用Optional值
它的值不存在的情况下会产生一个可代替物,而只有值存在的情况下才会使用这个值;
public T orElse(T other) 返回值如果存在,否则返回其他。
1 public T orElse(T other) { 2 return value != null ? value : other; 3 }
public static <T> Optional<T> empty() 返回一个空的可选实例
1 private static final Optional<?> EMPTY = new Optional<>(); 2 public static<T> Optional<T> empty() { 3 Optional<T> t = (Optional<T>) EMPTY; 4 return t; 5 }
public T orElseGet(Supplier<? extends T> other) 如果当前值存在就返回该值,否则调用其他值并返回该调用的结果。
1 public T orElseGet(Supplier<? extends T> other) { 2 return value != null ? value : other.get(); 3 }
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X extends Throwable 返回包含的值(如果存在),否则抛出由供应商创建的异常。
1 public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { 2 if (value != null) { 3 return value; 4 } else { 5 throw exceptionSupplier.get(); 6 } 7 }
public <U> Optional<U> map(Function<? super T,? extends U> mapper) 如果存在值,则应用提供的映射函数,如果结果不为空,则返回一个描述结果的可选项。否则返回一个空的可选。
1 public<U> Optional<U> map(Function<? super T, ? extends U> mapper) { 2 Objects.requireNonNull(mapper); 3 if (!isPresent()) 4 return empty(); 5 else { 6 return Optional.ofNullable(mapper.apply(value)); 7 } 8 }
public void ifPresent(Consumer<? super T> consumer) 如果存在值,则使用该值调用指定的消费者,否则不执行任何操作
1 public void ifPresent(Consumer<? super T> consumer) { 2 if (value != null) 3 consumer.accept(value); 4 }
1.7.2. 实例
1 public class Demo09 { 2 3 private static final String filePath = "G:\Idea\src\com\itheima05\Test_JavaSE\Test_20171214\word.txt"; 4 5 public static void main(String[] args) throws Exception { 6 7 String contens = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8); 8 List<String> words = Arrays.asList(contens.split("\PL+")); 9 10 //获取流中的最大值,(忽略大小写) 11 Optional<String> maxValue = words.stream().max(String::compareToIgnoreCase); 12 System.out.println("maxValue:"+maxValue.orElse("")); 13 14 //orElse实例 15 Optional<String> firstWord = words.stream() 16 .filter(w -> w.contains("pro")) 17 .findFirst(); 18 System.out.println(firstWord.orElse("No word" + "contains pro")); 19 20 //empty:返回一个空的可选实例(optionalValue == null) 21 Optional<String> optionalValue = firstWord.empty(); 22 String orElseValue = optionalValue.orElse("N/A"); 23 System.out.println("orElseValue:"+orElseValue); 24 25 //orElseGet实例 26 String orElseGetValue = optionalValue.orElseGet(() -> Locale.getDefault().getDisplayName()); 27 System.out.println("orElseGetValue:"+orElseGetValue); 28 29 //orElseThrow实例 30 try { 31 String orElseThrowValue = optionalValue.orElseThrow(IllegalStateException::new); 32 System.out.println("orElseThrowValue:"+orElseThrowValue); 33 } catch (Throwable e) { 34 e.printStackTrace(); 35 } 36 37 //ifPresent实例 38 Optional<String> ifPresentValue = words.stream().filter(w -> w.contains("Quite")).findFirst(); 39 ifPresentValue.ifPresent(s -> System.out.println("s:" + "contains Quite")); 40 41 HashSet<String> results = new HashSet<>(); 42 ifPresentValue.ifPresent(results :: add); 43 44 //调用ifPresent时,从该函数不会返回任何值,如果想要处理函数的结果,应该使用map 45 Optional<Boolean> mapValue = ifPresentValue.map(results::add); 46 Optional<Integer> sizeValue = ifPresentValue.map(s -> results.size()); 47 Optional<String> iteratorValue = ifPresentValue.map(s -> results.iterator().next()); 48 System.out.println("mapValue:"+mapValue); 49 System.out.println("sizeValue:"+sizeValue); 50 System.out.println("iteratorValue:"+iteratorValue); 51 //mapValue具有三种值:在ifPresentValue存在的情况下包装在Optional中的true或false, 52 //以及ifPresentValue不存在的情况下的空Optional 53 } 54 }
1.7.3. 不适合使用Optional值的方式
public T get() 如果此可选中存在值,则返回该值,否则引发NoSuchElementException;
Get方法会在Optional值存在的情况下获得其中包装元素,或者在不存在的情况下抛出一个NoSuchElementException对象;
public boolean isPresent() 如果该Optional不为空,则返回true;
1 public class Demo10 { 2 3 private static final String filePath = "G:\Idea\src\com\itheima05\Test_JavaSE\Test_20171214\word.txt"; 4 5 public static void main(String[] args) throws Exception { 6 7 String contens = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8); 8 List<String> words = Arrays.asList(contens.split("\PL+")); 9 Optional<String> word = words.stream().filter(w -> w.contains("Quite")).findFirst(); 10 if(word.isPresent()){ 11 String w = word.get().toUpperCase(); 12 System.out.println(w); 13 }else{ 14 String orElseValue = word.orElse("not contains Quite"); 15 System.out.println("orElseValue:"+orElseValue); 16 } 17 } 18 }
1.7.4. 创建Optional值
public static <T> Optional<T> ofNullable(T value) 该方法被用来作为可能出现的null值和可选值之间的桥梁,Optional. ofNullable(obj)会在obj不为null的情况下返回Optional.of(obj),否则会返回Optional.empty();
public static <T> Optional<T> of(T value) 返回指定的当前非空值的Optional。
public static <T> Optional<T> empty() 返回一个空的可选实例。 没有值是这个可选的。
1 public class Demo11 { 2 3 public static void main(String[] args) { 4 5 //Optional.ofNullable(obj):obj不为空,返回一个Optional.of(obj) 6 String s = "123"; 7 Optional<String> s1 = Optional.ofNullable(s); 8 System.out.println(s1); //输出:Optional[123] 9 //Optional.ofNullable(obj):obj为空,返回一个Optional.empty(); 10 String ss1 = ""; 11 Optional<String> ss = Optional.ofNullable(ss1); 12 System.out.println(ss); //输出:Optional[] 13 } 14 }
1.7.5. 用faltMAP来构建Optional值的函数
假设你有一个可以产生Optional<T>对象的方法F,并且目标类型T具有一个可以产生Optional<U>对象的方法G;如果都是普通的方法,那么可以通过调用s.f().g()来将他们组合起来,但是这种组合没法工作;
需要这样调用:
Optional<U> result = s.f().flatmap(T :: G);
1 public class Demo12 { 2 3 public static void main(String[] args) { 4 5 //Demo12 :: squareRoot,这种格式表示:Demo12类中名为squareRoot的方法 6 Optional<Double> result = inverse(2.0).flatMap(Demo12 :: squareRoot); 7 if(result.isPresent()){ 8 Double orElseValue = result.orElse(0.0); 9 System.out.println("orElseValue:"+orElseValue); 10 } 11 12 //实例2 13 System.out.println("实例1:"+inverse(4.0).flatMap(Demo12 :: squareRoot)); 14 System.out.println("实例2:"+inverse(-1.0).flatMap(Demo12 :: squareRoot)); 15 System.out.println("实例3:"+inverse(0.0).flatMap(Demo12 :: squareRoot)); 16 17 System.out.println("实例4:"+Optional.of(-0.4).flatMap(Demo12 :: inverse).flatMap(Demo12 :: squareRoot)); 18 } 19 20 public static Optional<Double> inverse(Double x){ 21 22 return x == 0 ? Optional.empty() : Optional.of(1/x); 23 } 24 //平方根计算 25 public static Optional<Double> squareRoot(Double x){ 26 27 return x < 0 ? Optional.empty() : Optional.of(Math.sqrt(x)); 28 } 29 }