Java Optional解决空指针异常总结(java 8 功能)
1、概述
Java8的版本,新增了Optional和[Lambda]表达式,Optional主要用于作为返回类型(主要解决的问题是臭名昭著的空指针异常
(NullPointerException)),并将其与流(或返回可选的方法)相结合以构建连贯API。
但是,有些情况可以被认为是陷阱,因为它们会降低代码的质量,甚至导致意想不到的错误。总结以下26个例子,以避免这些陷阱。
2、目录
[第1项:决不将Null分配给可选变量]
[第2项:调用Optional.get()之前,确保Optional具有值]
[第3项:当不存在任何值时,通过Optional.orElse()方法设置/返回已经构造的默认对象]
[第4项:不存在任何值时,通过Optional.orElseGet()方法设置/返回不存在的默认对象]
[第5项:当不存在任何值时,自Java10起通过orElseThrow()抛出java.util.NoSuchElementException异常]
[第6项:当不存在任何值时,通过orElseThrow(Supplier<?extendedX>exceptionSupplier)引发显式异常]
[第7项:当你有可选的并且需要空引用时,请使用orElse(null)]
[第8项:使用可选(如果存在)。如果不存在,则什么也不做。这是Optional.ifPresent()的工作。]
[第9项:使用可选(如果存在)。如果不存在,请执行基于空的操作。这是Optional.ifPresentElse(),Java9的工作。]
[第10项:当值存在时,设置/返回该可选项。如果不存在任何值,则设置/返回另一个可选项。这是Java9的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为空,则返回一个布尔值。首选Java11,Optional.isEmpty()]
第1项:决不将Null分配给可选变量
避免:
//避免 publicOptionalfetchCart(){ Optional emptyCart=null; ... }
首选:
//首选 publicOptionalfetchCart(){ Optional emptyCart=Optional.empty(); ... }
首选Optional.empty()初始化Optional而不是null值。Optional只是一个容器/盒子,用初始化它是没有意义的null。
第2项:调用Optional.get()之前,确保Optional具有值
如果出于某种原因你决定使用Optional.get(),那么请不要忘记必须Optional在此调用之前证明该值存在。通常,将通过基于该Optional.isPresent()方法添加检查(条件)来执行此操作。Optional.get()在某些时候容易被弃用。
避免:
//避免 Optionalcart=...;//这很容易是空的 ... //如果“cart”是空的,那么这段代码将抛出一个java.util.NoSuchElementException CartmyCart=cart.get();
首选:
//首选 if(cart.isPresent()){ CartmyCart=cart.get(); ... }else{ ...//做一些不调用carter.get()的事情 }
第3项:当不存在任何值时,通过Optional.orElse()方法设置/返回已经构造的默认对象
使用Optional.orElse()方法代表了用于设置/返回值的isPresent()-get()对的优雅替代。这里重要的一点是,即使是非空可选的,也要计算oforElse()参数。这意味着即使不使用它,也会对它进行评估,这是一种性能损失。在这个上下文中,useorElse()只在参数(默认对象)已经构造完成时才使用。在其他情况下,请依赖第4项。
避免:
//避免 publicstaticfinalStringUSER_STATUS="UNKNOWN"; ... publicStringfindUserStatus(longid){ Optionalstatus=...;//容易返回一个空的Optional if(status.isPresent()){ returnstatus.get(); }else{ returnUSER_STATUS; } }
首选:
//首选 publicstaticfinalStringUSER_STATUS="UNKNOWN"; ... publicStringfindUserStatus(longid){ Optionalstatus=...;//容易返回一个空的Optional returnstatus.orElse(USER_STATUS); }
第4项:不存在任何值时,通过Optional.orElseGet()方法设置/返回不存在的默认对象
使用theOptional.orElseGet()方法表示另一种用于设置/返回值的替代theisPresent()-get()对的优雅方法。这里重要的一点是,参数oforElseGet()是Java8新特性。这意味着作为参数传递的Suppliermethod只在Optionalvalue不存在时执行。因此,这有助于避免创建对象和执行在出现Optionalvalue时不需要的代码时的orElse()性能损失。
避免:
//避免 publicStringcomputeStatus(){ ...//一些用来计算状态的代码 } publicStringfindUserStatus(longid){ Optionalstatus=...;//容易返回一个空的Optional if(status.isPresent()){ returnstatus.get(); }else{ returncomputeStatus(); } }
另外,请避免:
//避免 publicStringcomputeStatus(){ ...//一些用来计算状态的代码 } publicStringfindUserStatus(longid){ Optionalstatus=...;//容易返回一个空的Optional //即使“status”不是空的,也会调用computeStatus() returnstatus.orElse(computeStatus()); }
首选:
publicStringcomputeStatus(){ ...//somecodeusedtocomputestatus } publicStringfindUserStatus(longid){ Optionalstatus=...;//容易返回一个空的Optional //仅当“status”为空时才调用computeStatus() returnstatus.orElseGet(this::computeStatus); }
第5项:当不存在任何值时,自Java10起通过orElseThrow()抛出java.util.NoSuchElementException异常
使用该Optional.orElseThrow()方法代表了该方法的另一种优雅替代方法isPresent()-get()。有时,当Optional不存在值时,你要做的就是抛出java.util.NoSuchElementException异常。从Java10开始,这可以通过orElseThrow()不带参数的方法来完成。对于Java8和9,请考虑第6项。
避免:
publicStringfindUserStatus(longid){ Optionalstatus=...;//容易返回一个空的Optional if(status.isPresent()){ returnstatus.get(); }else{ thrownewNoSuchElementException(); } }
首选:
publicStringfindUserStatus(longid){ Optionalstatus=...;//容易返回一个空的Optional returnstatus.orElseThrow(); }
第6项:当不存在任何值时,通过orElseThrow(Supplier<?extendedX>exceptionSupplier)引发显式异常
在Java10中,对于java.util.NoSuchElementException,请使用orElseThrow(),如第5项所示。使用该Optional.orElseThrow(Supplier<?extendsX>exceptionSupplier)方法代表了该方法的另一种优雅替代方法isPresent()-get()。有时,当Optional不存在值时,你要做的就是抛出一个明确的异常。从Java10开始,如果该异常java.util.NoSuchElementException仅依赖于orElseThrow()不带参数的方法-第5项。
避免:
publicStringfindUserStatus(longid){ Optionalstatus=...;//容易返回一个空的Optional if(status.isPresent()){ returnstatus.get(); }else{ thrownewIllegalStateException(); } }
首选:
publicStringfindUserStatus(longid){ Optionalstatus=...;//容易返回一个空的Optional returnstatus.orElseThrow(IllegalStateException::new); }
第7项:当您有可选的并且需要空引用时,请使用orElse(null)
如果你有Optional需要提供null参考的,请使用orElse(null)。否则,请避免orElse(null)。orElse(null)当我们有一个Optional,并且需要null在某些情况下调用一个接受引用的方法时,就会发生典型的使用情况。例如,让我们看一下Method.invoke()JavaReflectionAPI。此方法的第一个参数是要在其上调用此特定方法的对象实例。如果方法是static,第一个参数,则应为null。
避免:
MethodmyMethod=...; ... //包含MyClass的实例,如果“myMethod”是静态的,则为空 OptionalinstanceMyClass=...; ... if(instanceMyClass.isPresent()){ myMethod.invoke(instanceMyClass.get(),...); }else{ myMethod.invoke(null,...); }
首选:
MethodmyMethod=...; ... //包含MyClass的实例,如果“myMethod”是静态的,则为空 OptionalinstanceMyClass=...; ... myMethod.invoke(instanceMyClass.orElse(null),...);
第8项:使用可选(如果存在)。如果不存在,则什么也不做。这是Optional.ifPresent()的工作。
当你只需要使用值时,Optional.ifPresent()是isPresent()-get()paid的不错选择。如果没有值,则不执行任何操作。
避免:
Optionalstatus=...; ... if(status.isPresent()){ System.out.println("Status:"+status.get()); }
首选:
Optionalstatus...; ... status.ifPresent(System.out::println);
第9项:使用可选(如果存在)。如果不存在,请执行基于空的操作。这是Optional.ifPresentElse(),Java9的工作。
从Java9开始,它Optional.ifPresentOrElse()是isPresent()-get()配对的不错选择。这与ifPresent()方法类似,只不过它也覆盖else分支。
避免:
Optionalstatus=...; if(status.isPresent()){ System.out.println("Status:"+status.get()); }else{ System.out.println("Statusnotfound"); }
首选:
Optionalstatus=...; status.ifPresentOrElse( System.out::println, ()->System.out.println("Statusnotfound") );
第10项:当值存在时,设置/返回该可选项。如果不存在任何值,则设置/返回另一个可选项。这是Java9的Optional.or()的工作。
有时,对于非空,Optional,我们想设置/返回那个Optional。当我们Optional为空时,我们想执行其他操作,该操作也返回一个Optional。该orElse()和orElseGet()方法不能做到这一点,因为两者都将返回展开值。现在该介绍Java9Optional.or()方法了,该方法能够返回Optional描述值。否则,它将返回Optional提供功能产生的结果。
避免:
publicOptionalfetchStatus(){ Optional status=...; Optional defaultStatus=Optional.of("PENDING"); if(status.isPresent()){ returnstatus; }else{ returndefaultStatus; } }
另外,请避免:
publicOptionalfetchStatus(){ Optional status=...; returnstatus.orElseGet(()->Optional. of("PENDING")); }
首选:
publicOptionalfetchStatus(){ Optional status=...; Optional defaultStatus=Optional.of("PENDING"); returnstatus.or(()->defaultStatus); //或者,不定义“defaultStatus” returnstatus.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
避免:
Listproducts=...; Optional product=products.stream() .filter(p->p.getPrice() 另外,请避免:
Listproducts=...; Optional product=products.stream() .filter(p->p.getPrice() 首选:
Listproducts=...; returnproducts.stream() .filter(p->p.getPrice() 例子2
避免:
Optionalcart=...; Productproduct=...; ... if(!cart.isPresent()|| !cart.get().getItems().contains(product)){ thrownewNoSuchElementException(); } 首选:
Optionalcart=...; Productproduct=...; ... cart.filter(c->c.getItems().contains(product)).orElseThrow(); 第12项:避免仅出于获取价值的目的而链接可选方法
有时,我们倾向于“过度使用”事物。意味着我们有一个东西,例如Optional,并且到处都可以看到用例。在的情况下Optional,常见的情况是出于获得价值的单一目的而链接其方法。避免这种做法,而是依靠简单明了的代码。
避免:
publicStringfetchStatus(){ Stringstatus=...; returnOptional.ofNullable(status).orElse("PENDING"); }首选:
publicStringfetchStatus(){ Stringstatus=...; returnstatus==null?"PENDING":status; }第13项:不要声明任何类型的可选字段
请勿Optional在方法(包括setters)或构造函数参数中使用。
请记住,这Optional并不是要用于字段,并且不会实现Serializable。该Optional班是明确不打算用作一个JavaBean的属性。
避免:
publicclassCustomer{ [access_modifier][static][final]Optionalzip; [access_modifier][static][final]Optional zip=Optional.empty(); ... } 首选:
publicclassCustomer{ [access_modifier][static][final]Stringzip; [access_modifier][static][final]Stringzip=""; ... }第14项:在构造函数参数中不要使用可选
请勿将其Optional用作字段或方法(包括setters)的参数。
这是违背Optional意图的另一种用法。Optional用另一种抽象级别包装对象,在这种情况下,只需添加额外的样板代码。
避免:
publicclassCustomer{ privatefinalStringname;//不可能为null privatefinalOptionalpostcode;//可能为null publicCustomer(Stringname,Optional postcode){ this.name=Objects.requireNonNull(name,()->"名称不能为空"); this.postcode=postcode; } publicOptional getPostcode(){ returnpostcode; } ... } 首选:
publicclassCustomer{ privatefinalStringname; privatefinalStringpostcode; publicCart(Stringname,Stringpostcode){ this.name=Objects.requireNonNull(name,()->"名称不能为空"); this.postcode=postcode; } publicOptionalgetPostcode(){ returnOptional.ofNullable(postcode); } ... } 如你所见,getter现在返回Optional。不要以这个示例作为转换所有此类getter的规则。多数情况下,getter返回集合或数组,在这种情况下,他们更喜欢返回空集合/数组而不是Optional。
我认为,通常将其用作获取方法的返回值肯定会过度使用。
第15项:在Setters参数中不要使用可选
Optional不能用作JavaBean的属性或持久属性类型。Optional不是Serializable。Optional在二传手中使用是另一种反模式。通常,我看到它用作持久属性类型(将实体属性映射为Optional)。但是,可以Optional在域模型实体中使用,如以下示例所示。
避免:
@Entity publicclassCustomerimplementsSerializable{ privatestaticfinallongserialVersionUID=1L; ... @Column(name="customer_zip") privateOptionalpostcode;//optional字段,因此可能为空 publicOptional getPostcode(){ returnpostcode; } publicvoidsetPostcode(Optional postcode){ this.postcode=postcode; } ... } 首选:
@Entity publicclassCustomerimplementsSerializable{ privatestaticfinallongserialVersionUID=1L; ... @Column(name="customer_zip") privateStringpostcode; publicOptionalgetPostcode(){ returnOptional.ofNullable(postcode); } publicvoidsetPostcode(Stringpostcode){ this.postcode=postcode; } ... } 第16项:在方法参数中不要使用可选
不要Optional用作字段或设置器和构造函数的参数。Optional在in方法中使用参数是另一个常见错误。这将导致不必要的复杂代码。负责检查参数,而不是强制调用站点创建Optional。这种做法会使代码混乱,并可能导致依赖性。随着时间的流逝,您将在所有地方使用它。请记住,这Optional只是另一个对象(容器),而且价它消耗的内存是强引用的4倍!但是,你可以用,视情况而定。
避免:
publicvoidrenderCustomer(Cartcart,Optionalrenderer, Optional name){ if(cart==null){ thrownewIllegalArgumentException("Cart不能为空"); } RenderercustomerRenderer=renderer.orElseThrow( ()->newIllegalArgumentException("Renderer不能为空") ); StringcustomerName=name.orElseGet(()->"anonymous"); ... } //调用这个是错误的 renderCustomer(cart,Optional. of(CoolRenderer::new),Optional.empty()); 首选:
publicvoidrenderCustomer(Cartcart,Rendererrenderer,Stringname){ if(cart==null){ thrownewIllegalArgumentException("Cart不能为空"); } if(renderer==null){ thrownewIllegalArgumentException("Renderer不能为空"); } StringcustomerName=Objects.requireNonNullElseGet(name,()->"anonymous"); ... } //调用这个方法 renderCustomer(cart,newCoolRenderer(),null);另外,更喜欢(依靠NullPointerException):
publicvoidrenderCustomer(Cartcart,Rendererrenderer,Stringname){ Objects.requireNonNull(cart,"Cart不能为空"); Objects.requireNonNull(renderer,"Renderer不能为空"); StringcustomerName=Objects.requireNonNullElseGet(name,()->"anonymous"); ... } //调用这个方法 renderCustomer(cart,newCoolRenderer(),null);另外,更喜欢(避免NullPointerException和使用IllegalArgumentException或其他异常):
publicfinalclassMyObjects{ privateMyObjects(){ thrownewAssertionError("Cannotcreateinstancesforyou!"); } publicstaticTrequireNotNullOrElseThrow(Tobj, SupplierexceptionSupplier)throwsX{ if(obj!=null){ returnobj; }else{ throwexceptionSupplier.get(); } } } publicvoidrenderCustomer(Cartcart,Rendererrenderer,Stringname){ MyObjects.requireNotNullOrElseThrow(cart, ()->newIllegalArgumentException("Cartcannotbenull")); MyObjects.requireNotNullOrElseThrow(renderer, ()->newIllegalArgumentException("Renderercannotbenull")); StringcustomerName=Objects.requireNonNullElseGet(name,()->"anonymous"); ... } //调用这个方法 renderCustomer(cart,newCoolRenderer(),null) 第17项:不要使用Optional的返回空的集合或数组
支持返回一个空的集合/数组。考虑到这一点,依靠Collections.emptyList(),emptyMap()和emptySet()。
为了保持代码的清洁,轻便避免返回Optional的null或空的集合/数组。最好返回一个空数组或集合。
避免:
publicOptional>fetchCartItems(longid){ Cartcart=...; List
items=cart.getItems();//这个可能会返回null returnOptional.ofNullable(items); } 首选:
publicListfetchCartItems(longid){ Cartcart=...; List items=cart.getItems();//这个可能会返回null returnitems==null?Collections.emptyList():items; } 第18项:避免在集合中使用Optional
见示例
避免:
Map>items=newHashMap<>(); items.put("I1",Optional.ofNullable(...)); items.put("I2",Optional.ofNullable(...)); ... Optional item=items.get("I1"); if(item==null){ System.out.println("找不到这把钥匙"); }else{ StringunwrappedItem=item.orElse("NOTFOUND"); System.out.println("Keyfound,Item:"+unwrappedItem); } 首选(Java8):
Mapitems=newHashMap<>(); items.put("I1","Shoes"); items.put("I2",null); ... //getanitem Stringitem=get(items,"I1");//Shoes Stringitem=get(items,"I2");//null Stringitem=get(items,"I3");//NOTFOUND privatestaticStringget(Map map,Stringkey){ returnmap.getOrDefault(key,"NOTFOUND"); } 还可以依赖其他方法,例如:
- containsKey()方法
- 通过扩展实现简单HashMap
- Java8computeIfAbsent()方法
- ApacheCommonsDefaultedMap
通过将此示例外推到其他集合,我们可以得出结论,总有比Optional在集合中使用更好的解决方案。
而且,甚至更糟:
Map,String>items=newHashMap<>(); Map ,Optional >items=newHashMap<>(); 第19项:不要混淆Optional.of()和Optional.ofNullable()
混淆或错误地使用Optional.of而不是Optional.ofNullable,反之亦然,可能会导致令人不快的问题。作为此处的关键,请记住Optional.of(null)会抛出NullPointerException,而Optional.ofNullable(null)会导致Optional.empty。
使用Optional.of代替Optional.ofNullable示例
避免:
//AVOID publicOptionalfetchItemName(longid){ StringitemName=...;//这可能导致null ... returnOptional.of(itemName);//如果“itemName”为空,则抛出NPE:( } 首选:
publicOptionalfetchItemName(longid){ StringitemName=...;//这可能导致null ... returnOptional.ofNullable(itemName);//没有NPE风险 } 使用Optional.ofNullable代替Optional.of示例
避免:
returnOptional.ofNullable("PENDING");//ofNullable不会增加任何值首选:
returnOptional.of("PENDING");//没有NPE风险第20项:避免使用可选的
,并选择非通用的OptionalInt,OptionalLong或OptionalDouble
除非你有盒装原语,避免特定需求Optional<T>,并选择非通用OptionalInt,OptionalLong或OptionalDouble。
装箱和拆箱是昂贵的操作,容易导致性能下降。为了消除这种风险,我们可以依靠OptionalInt,OptionalLong和OptionalDouble。这些是基本类型的包装int,long,和double。
避免使用(仅在需要装箱的原语时使用):
Optionalprice=Optional.of(50); Optional price=Optional.of(50L); Optional price=Optional.of(50.43d); 首选:
OptionalIntprice=OptionalInt.of(50);//打开通过getAsInt() OptionalLongprice=OptionalLong.of(50L);//打开通过getAsLong() OptionalDoubleprice=OptionalDouble.of(50.43d);//打开通过getAsDouble()第21项:无需包装主张平等的任择方案
有两个Optionals在assertEquals()不需要解开值。这是适用的,因为Optional#equals()比较包装的值,而不是Optional对象。
Optional.equals()源代码:
@Override publicbooleanequals(Objectobj){ if(this==obj){ returntrue; } if(!(objinstanceofOptional)){ returnfalse; } Optional>other=(Optional>)obj; returnObjects.equals(value,other.value); }避免:
OptionalactualItem=Optional.of("Shoes"); Optional expectedItem=Optional.of("Shoes"); assertEquals(expectedItem.get(),actualItem.get()); 首选:
OptionalactualItem=Optional.of("Shoes"); Optional expectedItem=Optional.of("Shoes"); assertEquals(expectedItem,actualItem); 第22项:通过Map()和flatMap()转换值
的Optional.map()和Optional.flatMap()是用于将非常方便的办法Optional值。该map()方法将函数参数应用于值,然后返回包装在中的结果Optional,而通过比较,该flatMap()方法采用应用于值的函数参数,Optional然后直接返回结果。
使用map()
例子1避免:
Optionallowername...;//可能是空的 //transformnametouppercase Optional uppername; if(lowername.isPresent()){ uppername=Optional.of(lowername.get().toUpperCase()); }else{ uppername=Optional.empty(); } 首选:
Optionallowername...;//可能是空的 //将名称转换为大写 Optional uppername=lowername.map(String::toUpperCase); 例子2
避免:
Listproducts=...; Optional product=products.stream() .filter(p->p.getPrice()<50) .findFirst(); Stringname; if(product.isPresent()){ name=product.get().getName().toUpperCase(); }else{ name="NOTFOUND"; } //getName()返回一个非空字符串 publicStringgetName(){ returnname; } 首选:
Listproducts=...; Stringname=products.stream() .filter(p->p.getPrice()<50) .findFirst() .map(Product::getName) .map(String::toUpperCase) .orElse("NOTFOUND"); //getName()返回一个字符串 publicStringgetName(){ returnname; } 使用flatMap()
避免:
Listproducts=...; Optional product=products.stream() .filter(p->p.getPrice()<50) .findFirst(); Stringname=null; if(product.isPresent()){ name=product.get().getName().orElse("NOTFOUND").toUpperCase(); } //getName()returnOptional publicOptional getName(){ returnOptional.ofNullable(name); } 首选:
Listproducts=...; Stringname=products.stream() .filter(p->p.getPrice()<50) .findFirst() .flatMap(Product::getName) .map(String::toUpperCase) .orElse("NOTFOUND"); //getName()returnOptional publicOptional getName(){ returnOptional.ofNullable(name); } 第23项:使用filter()根据预定义的规则拒绝包装值
传递谓词(条件)作为参数并获取一个Optional对象。Optional如果满足条件,则使用首字母缩写;如果不满足条件,则使用空白字母Optional。使用filter()接受或拒绝包装的值是一种非常方便的方法,因为无需显式包装值就可以实现它。
避免:
publicbooleanvalidatePasswordLength(UseruserId){ Optionalpassword=...;//Userpassword if(password.isPresent()){ returnpassword.get().length()>5; } returnfalse; } 首选:
publicbooleanvalidatePasswordLength(UseruserId){ Optionalpassword=...;//Userpassword returnpassword.filter((p)->p.length()>5).isPresent(); } 第24项:我们是否需要将可选API与流API链接在一起?
如果是这样,则我们使用该Optional.stream()方法。从Java9开始,我们可以通过应用方法将Optional实例视为。当您需要将OptionalAPI与StreamAPI链接在一起时,这很有用。此方法创建一个元素或一个空元素(如果不存在)。此外,我们可以使用StreamAPI中可用的所有方法。Stream``Optional.stream()``Stream``Stream``Optional
避免:
publicListgetProductList(List productId){ returnproductId.stream() .map(this::fetchProductById) .filter(Optional::isPresent) .map(Optional::get) .collect(toList()); } publicOptional fetchProductById(Stringid){ returnOptional.ofNullable(...); } 首选:
publicListgetProductList(List productId){ returnproductId.stream() .map(this::fetchProductById) .flatMap(Optional::stream) .collect(toList()); } publicOptional fetchProductById(Stringid){ returnOptional.ofNullable(...); } 实际上,Optional.stream()让我们来代替filter()和map()用flatMap()。
另外,我们可以转换Optional为List:
publicstaticList convertOptionalToList(Optional optional){ returnoptional.stream().collect(toList()); } 第25项:避免对可选选项使用身份敏感的操作
这包括引用相等(==),基于身份哈希或同步。Optional类是一个基于价值的类作为LocalDateTime。
避免:
Productproduct=newProduct(); Optionalop1=Optional.of(product); Optional op2=Optional.of(product); //op1==op2=>false,expectedtrue if(op1==op2){... 首选:
Productproduct=newProduct(); Optionalop1=Optional.of(product); Optional op2=Optional.of(product); //op1.equals(op2)=>true,expectedtrue if(op1.equals(op2)){... 第26项:如果Optional为空,则返回一个布尔值。首选Java11,Optional.isEmpty()
从Java11开始,true如果方法Optional为,则可以很容易地返回aisEmpty()。
避免使用(Java11+):
//(Java11+) publicOptionalfetchCartItems(longid){ Cartcart=...;//thismaybenull ... returnOptional.ofNullable(cart); } publicbooleancartIsEmpty(longid){ Optional cart=fetchCartItems(id); return!cart.isPresent(); 首选(Java11+):
//(Java11 publicOptionalfetchCartItems(longid){ Cartcart=...;//thismaybenull ... returnOptional.ofNullable(cart); } publicbooleancartIsEmpty(longid){ Optional cart=fetchCartItems(id); returncart.isEmpty(); } 这就是总结的这26个例子,希望可以避免这些陷阱,永远不会出现:java.lang.NullPointerException
到此这篇关于JavaOptional解决空指针异常总结(java8功能)的文章就介绍到这了,更多相关JavaOptional空指针异常内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!