Java Optional解决空指针异常总结(java 8 功能)
赵雍 人气:11、概述
Java8的版本,新增了Optional和[Lambda]表达式,Optional主要用于作为返回类型(主要解决的问题是臭名昭著的空指针异常
(NullPointerException)),并将其与流(或返回可选的方法)相结合以构建连贯API。
但是,有些情况可以被认为是陷阱,因为它们会降低代码的质量,甚至导致意想不到的错误。总结以下26个例子,以避免这些陷阱。
2、 目 录
[第1项:决不将Null分配给可选变量]
[第2项:调用Optional.get()之前,确保Optional具有值]
[第3项:当不存在任何值时,通过Optional.orElse()方法设置/返回已经构造的默认对象]
[第4项:不存在任何值时,通过Optional.orElseGet()方法设置/返回不存在的默认对象]
[第5项:当不存在任何值时,自Java 10起通过orElseThrow()抛出java.util.NoSuchElementException异常]
[第6项:当不存在任何值时,通过orElseThrow(Supplier <?extended X> exceptionSupplier)引发显式异常]
[第7项:当你有可选的并且需要空引用时,请使用orElse(null)]
[第8项:使用可选(如果存在)。如果不存在,则什么也不做。这是Optional.ifPresent()的工作。]
[第9项:使用可选(如果存在)。如果不存在,请执行基于空的操作。这是Optional.ifPresentElse(),Java 9的工作。]
[第10项:当值存在时,设置/返回该可选项。如果不存在任何值,则设置/返回另一个可选项。这是Java 9的Optional.or()的工作。]
[第11项:Optional.orElse / orElseXXX是Lambdas中的isPresent()-get()完美替代]
[第12项:避免仅出于获取价值的目的而链接可选方法]
[第13项:不要声明任何类型的可选字段]
[第14项:在构造函数参数中不要使用可选]
[第15项:在Setters参数中不要使用可选]
[第16项:在方法参数中不要使用可选]
[第17项:不要使用Optional 的返回空的集合或数组]
[第18项:避免在集合中使用Optional]
[第19项:不要混淆Optional.of()和Optional.ofNullable()]
[第20项:避免使用可选的,并选择非通用的OptionalInt,OptionalLong或OptionalDouble]
[第21项:无需包装主张平等的任择方案]
[第22项:通过Map()和flatMap()转换值]
[第23项:使用filter()根据预定义的规则拒绝包装值]
[第24项:我们是否需要将可选API与流API链接在一起?]
[第25项:避免对可选选项使用身份敏感的操作]
[第26项:如果Optional为空,则返回一个布尔值。首选Java 11,Optional.isEmpty()]
第1项:决不将Null分配给可选变量
避免:
// 避免 public Optional<Cart> fetchCart() { Optional<Cart> emptyCart = null; ... }
首选:
// 首选 public Optional<Cart> fetchCart() { Optional<Cart> emptyCart = Optional.empty(); ... }
首选Optional.empty()初始化 Optional而不是null值。Optional只是一个容器/盒子,用初始化它是没有意义的null。
第2项:调用Optional.get()之前,确保Optional具有值
如果出于某种原因你决定使用Optional.get(),那么请不要忘记必须Optional在此调用之前证明该值存在。通常,将通过基于该Optional.isPresent()方法添加检查(条件)来执行此操作。Optional.get()在某些时候容易被弃用。
避免:
// 避免 Optional<Cart> cart = ... ; // 这很容易是空的 ... // 如果“cart”是空的,那么这段代码将抛出一个java.util.NoSuchElementException Cart myCart = cart.get();
首选:
// 首选 if (cart.isPresent()) { Cart myCart = cart.get(); ... } else { ... // 做一些不调用carter .get()的事情 }
第3项:当不存在任何值时,通过Optional.orElse()方法设置/返回已经构造的默认对象
使用Optional.orElse()方法代表了用于设置/返回值的isPresent()-get()对的优雅替代。这里重要的一点是,即使是非空可选的,也要计算oforElse()参数。这意味着即使不使用它,也会对它进行评估,这是一种性能损失。在这个上下文中,useorElse()只在参数(默认对象)已经构造完成时才使用。在其他情况下,请依赖第4项。
避免:
// 避免 public static final String USER_STATUS = "UNKNOWN"; ... public String findUserStatus(long id) { Optional<String> status = ... ; // 容易返回一个空的 Optional if (status.isPresent()) { return status.get(); } else { return USER_STATUS; } }
首选:
// 首选 public static final String USER_STATUS = "UNKNOWN"; ... public String findUserStatus(long id) { Optional<String> status = ... ; // 容易返回一个空的 Optional return status.orElse(USER_STATUS); }
第4项:不存在任何值时,通过Optional.orElseGet()方法设置/返回不存在的默认对象
使用theOptional.orElseGet()方法表示另一种用于设置/返回值的替代theisPresent()-get()对的优雅方法。这里重要的一点是,参数oforElseGet()是Java 8新特性。这意味着作为参数传递的Suppliermethod只在Optionalvalue不存在时执行。因此,这有助于避免创建对象和执行在出现Optionalvalue时不需要的代码时的orElse()性能损失。
避免:
// 避免 public String computeStatus() { ... // 一些用来计算状态的代码 } public String findUserStatus(long id) { Optional<String> status = ... ; // 容易返回一个空的 Optional if (status.isPresent()) { return status.get(); } else { return computeStatus(); } }
另外,请避免:
// 避免 public String computeStatus() { ... // 一些用来计算状态的代码 } public String findUserStatus(long id) { Optional<String> status = ... ; // 容易返回一个空的 Optional // 即使“status”不是空的,也会调用computeStatus() return status.orElse(computeStatus()); }
首选:
public String computeStatus() { ... // some code used to compute status } public String findUserStatus(long id) { Optional<String> status = ... ; // 容易返回一个空的 Optional // 仅当“status”为空时才调用computeStatus() return status.orElseGet(this::computeStatus); }
第5项:当不存在任何值时,自Java 10起通过orElseThrow()抛出java.util.NoSuchElementException异常
使用该Optional.orElseThrow()方法代表了该方法的另一种优雅替代方法isPresent()-get()。有时,当Optional不存在值时,你要做的就是抛出java.util.NoSuchElementException异常。从Java 10开始,这可以通过orElseThrow()不带参数的方法来完成。对于Java 8和9,请考虑第6项。
避免:
public String findUserStatus(long id) { Optional<String> status = ... ; // 容易返回一个空的 Optional if (status.isPresent()) { return status.get(); } else { throw new NoSuchElementException(); } }
首选:
public String findUserStatus(long id) { Optional<String> status = ... ; // 容易返回一个空的 Optional return status.orElseThrow(); }
第6项:当不存在任何值时,通过orElseThrow(Supplier <?extended X> exceptionSupplier)引发显式异常
在Java 10中,对于 java.util.NoSuchElementException,请使用 orElseThrow(),如第5项所示。使用该Optional.orElseThrow(Supplier<? extends X> exceptionSupplier)方法代表了该方法的另一种优雅替代方法isPresent()-get()。有时,当Optional不存在值时,你要做的就是抛出一个明确的异常。从Java 10开始,如果该异常java.util.NoSuchElementException仅依赖于orElseThrow()不带参数的方法-第5项。
避免:
public String findUserStatus(long id) { Optional<String> status = ... ; // 容易返回一个空的 Optional if (status.isPresent()) { return status.get(); } else { throw new IllegalStateException(); } }
首选:
public String findUserStatus(long id) { Optional<String> status = ... ; // 容易返回一个空的 Optional return status.orElseThrow(IllegalStateException::new); }
第7项:当您有可选的并且需要空引用时,请使用orElse(null)
如果你有Optional需要提供null参考的,请使用 orElse(null)。否则,请避免 orElse(null)。orElse(null)当我们有一个Optional,并且需要null在某些情况下调用一个接受引用的方法时,就会发生典型的使用情况。例如,让我们看一下Method.invoke()Java Reflection API。此方法的第一个参数是要在其上调用此特定方法的对象实例。如果方法是static,第一个参数,则应为null。
避免:
Method myMethod = ... ; ... // 包含MyClass的实例,如果“myMethod”是静态的,则为空 Optional<MyClass> instanceMyClass = ... ; ... if (instanceMyClass.isPresent()) { myMethod.invoke(instanceMyClass.get(), ...); } else { myMethod.invoke(null, ...); }
首选:
Method myMethod = ... ; ... // 包含MyClass的实例,如果“myMethod”是静态的,则为空 Optional<MyClass> instanceMyClass = ... ; ... myMethod.invoke(instanceMyClass.orElse(null), ...);
第8项:使用可选(如果存在)。如果不存在,则什么也不做。这是Optional.ifPresent()的工作。
当你只需要使用值时,Optional.ifPresent()是isPresent()-get()paid的不错选择。 如果没有值,则不执行任何操作。
避免:
Optional<String> status = ... ; ... if (status.isPresent()) { System.out.println("Status: " + status.get()); }
首选:
Optional<String> status ... ; ... status.ifPresent(System.out::println);
第9项:使用可选(如果存在)。如果不存在,请执行基于空的操作。这是Optional.ifPresentElse(),Java 9的工作。
从Java 9开始,它Optional.ifPresentOrElse()是isPresent()-get()配对的不错选择。这与ifPresent()方法类似, 只不过它也覆盖else分支。
避免:
Optional<String> status = ... ; if(status.isPresent()) { System.out.println("Status: " + status.get()); } else { System.out.println("Status not found"); }
首选:
Optional<String> status = ... ; status.ifPresentOrElse( System.out::println, () -> System.out.println("Status not found") );
第10项:当值存在时,设置/返回该可选项。如果不存在任何值,则设置/返回另一个可选项。这是Java 9的Optional.or()的工作。
有时,对于非空, Optional,我们想设置/返回那个 Optional。当我们Optional为空时,我们想执行其他操作,该操作也返回一个 Optional。该orElse()和orElseGet()方法不能做到这一点,因为两者都将返回展开值。现在该介绍Java 9 Optional.or()方法了,该方法能够返回Optional描述值。否则,它将返回Optional提供功能产生的结果。
避免:
public Optional<String> fetchStatus() { Optional<String> status = ... ; Optional<String> defaultStatus = Optional.of("PENDING"); if (status.isPresent()) { return status; } else { return defaultStatus; } }
另外,请避免:
public Optional<String> fetchStatus() { Optional<String> status = ... ; return status.orElseGet(() -> Optional.<String>of("PENDING")); }
首选:
public Optional<String> fetchStatus() { Optional<String> status = ... ; Optional<String> defaultStatus = Optional.of("PENDING"); return status.or(() -> defaultStatus); // 或者,不定义“defaultStatus” return status.or(() -> Optional.of("PENDING")); }
第11项:Optional.orElse / orElseXXX是Lambdas中的isPresent()-get()完美替代
这可用于获取链接的lambda,而不是被破坏的代码。考虑 ifPresent() 和 ifPresentOrElse() Java中9或 or() Java中9的方法,也是如此。某些特定于lambda的操作正在返回Optional(例如,findFirst(), findAny(), reduce(),...)。尝试Optional通过该isPresent()-get()对使用此方法是一种笨拙的方法,因为它可能需要您打破lambda链,用if语句污染代码,并考虑继续使用链。在这种情况下,orElse()and和orElseXXX()非常方便,因为它们可以直接在lambda表达式链中链接,并避免破坏代码。
例子1
避免:
List<Product> products = ... ; Optional<Product> product = products.stream() .filter(p -> p.getPrice() < price) .findFirst(); if (product.isPresent()) { return product.get().getName(); } else { return "NOT FOUND"; }
另外,请避免:
List<Product> products = ... ; Optional<Product> product = products.stream() .filter(p -> p.getPrice() < price) .findFirst(); return product.map(Product::getName) .orElse("NOT FOUND");
首选:
List<Product> products = ... ; return products.stream() .filter(p -> p.getPrice() < price) .findFirst() .map(Product::getName) .orElse("NOT FOUND");
例子2
避免:
Optional<Cart> cart = ... ; Product product = ... ; ... if(!cart.isPresent() || !cart.get().getItems().contains(product)) { throw new NoSuchElementException(); }
首选:
Optional<Cart> cart = ... ; Product product = ... ; ... cart.filter(c -> c.getItems().contains(product)).orElseThrow();
第12项:避免仅出于获取价值的目的而链接可选方法
有时,我们倾向于“过度使用”事物。意味着我们有一个东西,例如 Optional,并且到处都可以看到用例。在的情况下 Optional,常见的情况是出于获得价值的单一目的而链接其方法。避免这种做法,而是依靠简单明了的代码。
避免:
public String fetchStatus() { String status = ... ; return Optional.ofNullable(status).orElse("PENDING"); }
首选:
public String fetchStatus() { String status = ... ; return status == null ? "PENDING" : status; }
第13项:不要声明任何类型的可选字段
请勿 Optional 在方法(包括 setters)或构造函数参数中使用。
请记住,这Optional 并不是要用于字段,并且不会实现Serializable。该Optional班是明确不打算用作一个Java Bean的属性。
避免:
public class Customer { [access_modifier] [static] [final] Optional<String> zip; [access_modifier] [static] [final] Optional<String> zip = Optional.empty(); ... }
首选:
public class Customer { [access_modifier] [static] [final] String zip; [access_modifier] [static] [final] String zip = ""; ... }
第14项:在构造函数参数中不要使用可选
请勿将其 Optional 用作字段或方法(包括 setters)的参数。
这是违背Optional意图的另一种用法。 Optional用另一种抽象级别包装对象,在这种情况下,只需添加额外的样板代码。
避免:
public class Customer { private final String name; // 不可能为null private final Optional<String> postcode; //可能为null public Customer(String name, Optional<String> postcode) { this.name = Objects.requireNonNull(name, () -> "名称不能为空"); this.postcode = postcode; } public Optional<String> getPostcode() { return postcode; } ... }
首选:
public class Customer { private final String name; private final String postcode; public Cart(String name, String postcode) { this.name = Objects.requireNonNull(name, () -> "名称不能为空"); this.postcode = postcode; } public Optional<String> getPostcode() { return Optional.ofNullable(postcode); } ... }
如你所见,getter现在返回 Optional。不要以这个示例作为转换所有此类getter的规则。多数情况下,getter返回集合或数组,在这种情况下,他们更喜欢返回空集合/数组而不是 Optional。
我认为,通常将其用作获取方法的返回值肯定会过度使用。
第15项:在Setters参数中不要使用可选
Optional 不能用作Java Bean的属性或持久属性类型。 Optional 不是Serializable。Optional在二传手中使用是另一种反模式。通常,我看到它用作持久属性类型(将实体属性映射为 Optional)。但是,可以Optional在域模型实体中使用,如以下示例所示。
避免:
@Entity public class Customer implements Serializable { private static final long serialVersionUID = 1L; ... @Column(name="customer_zip") private Optional<String> postcode; // optional 字段, 因此可能为空 public Optional<String> getPostcode() { return postcode; } public void setPostcode(Optional<String> postcode) { this.postcode = postcode; } ... }
首选:
@Entity public class Customer implements Serializable { private static final long serialVersionUID = 1L; ... @Column(name="customer_zip") private String postcode; public Optional<String> getPostcode() { return Optional.ofNullable(postcode); } public void setPostcode(String postcode) { this.postcode = postcode; } ... }
第16项:在方法参数中不要使用可选
不要 Optional 用作字段或设置器和构造函数的参数。Optional在in方法中使用参数是另一个常见错误。这将导致不必要的复杂代码。负责检查参数,而不是强制调用站点创建 Optional。这种做法会使代码混乱,并可能导致依赖性。随着时间的流逝,您将在所有地方使用它。请记住,这Optional只是另一个对象(容器),而且价它消耗的内存是强引用的4倍!但是,你可以用,视情况而定。
避免:
public void renderCustomer(Cart cart, Optional<Renderer> renderer, Optional<String> name) { if (cart == null) { throw new IllegalArgumentException("Cart不能为空"); } Renderer customerRenderer = renderer.orElseThrow( () -> new IllegalArgumentException("Renderer 不能为空") ); String customerName = name.orElseGet(() -> "anonymous"); ... } //调用这个是错误的 renderCustomer(cart, Optional.<Renderer>of(CoolRenderer::new), Optional.empty());
首选:
public void renderCustomer(Cart cart, Renderer renderer, String name) { if (cart == null) { throw new IllegalArgumentException("Cart 不能为空"); } if (renderer == null) { throw new IllegalArgumentException("Renderer 不能为空"); } String customerName = Objects.requireNonNullElseGet(name, () -> "anonymous"); ... } // 调用这个方法 renderCustomer(cart, new CoolRenderer(), null);
另外,更喜欢(依靠NullPointerException):
public void renderCustomer(Cart cart, Renderer renderer, String name) { Objects.requireNonNull(cart, "Cart 不能为空"); Objects.requireNonNull(renderer, "Renderer 不能为空"); String customerName = Objects.requireNonNullElseGet(name, () -> "anonymous"); ... } // 调用这个方法 renderCustomer(cart, new CoolRenderer(), null);
另外,更喜欢(避免NullPointerException和使用IllegalArgumentException或其他异常):
public final class MyObjects { private MyObjects() { throw new AssertionError("Cannot create instances for you!"); } public static <T, X extends Throwable> T requireNotNullOrElseThrow(T obj, Supplier<? extends X> exceptionSupplier) throws X { if (obj != null) { return obj; } else { throw exceptionSupplier.get(); } } } public void renderCustomer(Cart cart, Renderer renderer, String name) { MyObjects.requireNotNullOrElseThrow(cart, () -> new IllegalArgumentException("Cart cannot be null")); MyObjects.requireNotNullOrElseThrow(renderer, () -> new IllegalArgumentException("Renderer cannot be null")); String customerName = Objects.requireNonNullElseGet(name, () -> "anonymous"); ... } // 调用这个方法 renderCustomer(cart, new CoolRenderer(), null)
第17项:不要使用Optional 的返回空的集合或数组
支持返回一个空的集合/数组。考虑到这一点,依靠 Collections.emptyList(), emptyMap()和emptySet()。
为了保持代码的清洁,轻便避免返回Optional的null或空的集合/数组。最好返回一个空数组或集合。
避免:
public Optional<List<String>> fetchCartItems(long id) { Cart cart = ... ; List<String> items = cart.getItems(); //这个可能会返回null return Optional.ofNullable(items); }
首选:
public List<String> fetchCartItems(long id) { Cart cart = ... ; List<String> items = cart.getItems(); // 这个可能会返回null return items == null ? Collections.emptyList() : items; }
第18项:避免在集合中使用Optional
见示例
避免:
Map<String, Optional<String>> items = new HashMap<>(); items.put("I1", Optional.ofNullable(...)); items.put("I2", Optional.ofNullable(...)); ... Optional<String> item = items.get("I1"); if (item == null) { System.out.println("找不到这把钥匙"); } else { String unwrappedItem = item.orElse("NOT FOUND"); System.out.println("Key found, Item: " + unwrappedItem); }
首选(Java 8):
Map<String, String> items = new HashMap<>(); items.put("I1", "Shoes"); items.put("I2", null); ... // get an item String item = get(items, "I1"); // Shoes String item = get(items, "I2"); // null String item = get(items, "I3"); // NOT FOUND private static String get(Map<String, String> map, String key) { return map.getOrDefault(key, "NOT FOUND"); }
还可以依赖其他方法,例如:
- containsKey()方法
- 通过扩展实现简单HashMap
- Java 8 computeIfAbsent()方法
- Apache CommonsDefaultedMap
通过将此示例外推到其他集合,我们可以得出结论,总有比Optional在集合中使用更好的解决方案。
而且,甚至更糟:
Map<Optional<String>, String> items = new HashMap<>(); Map<Optional<String>, Optional<String>> items = new HashMap<>();
第19项:不要混淆Optional.of()和Optional.ofNullable()
混淆或错误地使用 Optional.of而不是Optional.ofNullable,反之亦然,可能会导致令人不快的问题。作为此处的关键,请记住Optional.of(null)会抛出NullPointerException,而Optional.ofNullable(null)会导致 Optional.empty。
使用Optional.of代替Optional.ofNullable示例
避免:
// AVOID public Optional<String> fetchItemName(long id) { String itemName = ... ; // 这可能导致null ... return Optional.of(itemName); // 如果“itemName”为空,则抛出NPE :( }
首选:
public Optional<String> fetchItemName(long id) { String itemName = ... ; // 这可能导致null ... return Optional.ofNullable(itemName); // 没有NPE风险 }
使用Optional.ofNullable代替Optional.of示例
避免:
return Optional.ofNullable("PENDING"); // ofNullable不会增加任何值
首选:
return Optional.of("PENDING"); // 没有 NPE 风险
第20项:避免使用可选的<T>,并选择非通用的OptionalInt,OptionalLong或OptionalDouble
除非你有盒装原语,避免特定需求 Optional< T > ,并选择非通用 OptionalInt, OptionalLong或OptionalDouble。
装箱和拆箱是昂贵的操作,容易导致性能下降。为了消除这种风险,我们可以依靠 OptionalInt,OptionalLong 和OptionalDouble。这些是基本类型的包装int,long,和double。
避免使用(仅在需要装箱的原语时使用):
Optional<Integer> price = Optional.of(50); Optional<Long> price = Optional.of(50L); Optional<Double> price = Optional.of(50.43d);
首选:
OptionalInt price = OptionalInt.of(50); // 打开通过 getAsInt() OptionalLong price = OptionalLong.of(50L); // 打开通过 getAsLong() OptionalDouble price = OptionalDouble.of(50.43d); // 打开通过 getAsDouble()
第21项:无需包装主张平等的任择方案
有两个Optionals在assertEquals()不需要解开值。这是适用的,因为Optional#equals()比较包装的值,而不是Optional对象。
Optional.equals()源代码:
@Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof Optional)) { return false; } Optional<?> other = (Optional<?>) obj; return Objects.equals(value, other.value); }
避免:
Optional<String> actualItem = Optional.of("Shoes"); Optional<String> expectedItem = Optional.of("Shoes"); assertEquals(expectedItem.get(), actualItem.get());
首选:
Optional<String> actualItem = Optional.of("Shoes"); Optional<String> expectedItem = Optional.of("Shoes"); assertEquals(expectedItem, actualItem);
第22项:通过Map()和flatMap()转换值
的Optional.map()和Optional.flatMap()是用于将非常方便的办法Optional值。该map()方法将函数参数应用于值,然后返回包装在中的结果 Optional,而通过比较,该flatMap()方法采用应用于值的函数参数,Optional然后直接返回结果。
使用 map()
例子1
避免:
Optional<String> lowername ...; // 可能是空的 // transform name to upper case Optional<String> uppername; if (lowername.isPresent()) { uppername = Optional.of(lowername.get().toUpperCase()); } else { uppername = Optional.empty(); }
首选:
Optional<String> lowername ...; // 可能是空的 // 将名称转换为大写 Optional<String> uppername = lowername.map(String::toUpperCase);
例子2
避免:
List<Product> products = ... ; Optional<Product> product = products.stream() .filter(p -> p.getPrice() < 50) .findFirst(); String name; if (product.isPresent()) { name = product.get().getName().toUpperCase(); } else { name = "NOT FOUND"; } //getName()返回一个非空字符串 public String getName() { return name; }
首选:
List<Product> products = ... ; String name = products.stream() .filter(p -> p.getPrice() < 50) .findFirst() .map(Product::getName) .map(String::toUpperCase) .orElse("NOT FOUND"); // getName()返回一个字符串 public String getName() { return name; }
使用 flatMap()
避免:
List<Product> products = ... ; Optional<Product> product = products.stream() .filter(p -> p.getPrice() < 50) .findFirst(); String name = null; if (product.isPresent()) { name = product.get().getName().orElse("NOT FOUND").toUpperCase(); } // getName() return Optional public Optional<String> getName() { return Optional.ofNullable(name); }
首选:
List<Product> products = ... ; String name = products.stream() .filter(p -> p.getPrice() < 50) .findFirst() .flatMap(Product::getName) .map(String::toUpperCase) .orElse("NOT FOUND"); // getName() return Optional public Optional<String> getName() { return Optional.ofNullable(name); }
第23项:使用filter()根据预定义的规则拒绝包装值
传递谓词(条件)作为参数并获取一个 Optional 对象。Optional 如果满足条件,则使用首字母缩写;如果不满足条件,则使用空白 字母 Optional 。使用filter()接受或拒绝包装的值是一种非常方便的方法,因为无需显式包装值就可以实现它。
避免:
public boolean validatePasswordLength(User userId) { Optional<String> password = ...; // User password if (password.isPresent()) { return password.get().length() > 5; } return false; }
首选:
public boolean validatePasswordLength(User userId) { Optional<String> password = ...; // User password return password.filter((p) -> p.length() > 5).isPresent(); }
第24项:我们是否需要将可选API与流API链接在一起?
如果是这样,则我们使用该 Optional.stream() 方法。从Java 9开始,我们可以通过应用方法将Optional实例视为。当您需要将Optional API与Stream API链接在一起时,这很有用。此方法创建一个元素或一个空元素(如果不存在)。此外,我们可以使用Stream API中可用的所有方法。 Stream``Optional.stream()``Stream``Stream``Optional
避免:
public List<Product> getProductList(List<String> productId) { return productId.stream() .map(this::fetchProductById) .filter(Optional::isPresent) .map(Optional::get) .collect(toList()); } public Optional<Product> fetchProductById(String id) { return Optional.ofNullable(...); }
首选:
public List<Product> getProductList(List<String> productId) { return productId.stream() .map(this::fetchProductById) .flatMap(Optional::stream) .collect(toList()); } public Optional<Product> fetchProductById(String id) { return Optional.ofNullable(...); }
实际上,Optional.stream()让我们来代替filter()和 map()用 flatMap()。
另外,我们可以转换Optional为List:
public static <T> List<T> convertOptionalToList(Optional<T> optional) { return optional.stream().collect(toList()); }
第25项:避免对可选选项使用身份敏感的操作
这包括引用相等(==),基于身份哈希或同步。Optional类是一个基于价值的类作为 LocalDateTime。
避免:
Product product = new Product(); Optional<Product> op1 = Optional.of(product); Optional<Product> op2 = Optional.of(product); // op1 == op2 => false, expected true if (op1 == op2) { ...
首选:
Product product = new Product(); Optional<Product> op1 = Optional.of(product); Optional<Product> op2 = Optional.of(product); // op1.equals(op2) => true,expected true if (op1.equals(op2)) { ...
第26项:如果Optional为空,则返回一个布尔值。首选Java 11,Optional.isEmpty()
从Java 11开始,true如果方法Optional为,则可以很容易地返回a isEmpty()。
避免使用(Java 11+):
// (Java 11+) public Optional<String> fetchCartItems(long id) { Cart cart = ... ; // this may be null ... return Optional.ofNullable(cart); } public boolean cartIsEmpty(long id) { Optional<String> cart = fetchCartItems(id); return !cart.isPresent();
首选(Java 11+):
// (Java 11 public Optional<String> fetchCartItems(long id) { Cart cart = ... ; // this may be null ... return Optional.ofNullable(cart); } public boolean cartIsEmpty(long id) { Optional<String> cart = fetchCartItems(id); return cart.isEmpty(); }
这就是总结的这26个例子,希望可以避免这些陷阱,永远不会出现:java.lang.NullPointerException
加载全部内容