首页 >> 时尚

是时候庄重地和NullPointException说再见了

时间:2024-01-23 12:20:03

如:一个大的字符串,getContent()法则回到了个Optional取向,然后testCallOptional()法则作为初始化方,得到到赋参数后的操纵方式则:

public void testCallOptional() { Optional optional = getContent(); System.out.println("-------一个大字符串但会周报出现异常--------"); try { // 【缺失名词】实际上从Optional取向以前get()实质参数,这种效用与回到null取向然后实际上初始化是一样的效用 Content content = optional.get(); System.out.println(content); } catch (Exception e) { e.printStackTrace(); } System.out.println("-------侧面字符串但会周报出现异常--------");}private Optional getContent() { return Optional.ofNullable(null);}遗传物质字符串

上述字符串运行再次但会发现周报错了:

-------一个大字符串但会周报出现异常--------ja.util.NoSuchElementException: No value present at ja.util.Optional.get(Optional.ja:135) at com.veezean.skills.optional.OptionalService.testCallOptional(OptionalService.ja:47) at com.veezean.skills.optional.OptionalService.main(OptionalService.ja:58)-------侧面字符串但会周报出现异常--------遗传物质字符串

既然实际上初始化Optional.get()周报错,那就是初始化前加个假定就好咯?

public void testCallOptional2() { Optional optional = getContent(); // 用于前再行假定下特性是不是假定 if (optional.isPresent()) { Content content = optional.get(); System.out.println(content); }}遗传物质字符串

可执行一下,果然不周报错了。但是,这样一定会就是解决法则吗?这样跟实际上回到null然后用于前判自造(一个大的读到法)只不过也不曾啥相异,也并不但会让初始化方用于上去不够加的华丽与靠谱:

public void testNullReturn2() { Content content = getContent2(); if (content != null) { System.out.println(content.getValue()); }}遗传物质字符串

那怎么样才是确实的用于方式则呢,一个大一上去看下。

全面认识下Optional创建Optional取向

Optional取向,可以用来回应一个T各种类型取向的填充,或者也可以回应不是任何取向。Optional类得到了几个静态法则仅供取向的构建:

法则名

功能意义描述

empty()

特征一个无任何实质取向参数的自造Optional取向(可以理解为经营范围层次的null)

of(T t)

根据假定的取向,特征一个此取向的填充Optional取向,劝注意进参t不能为null,否则但会自造常量

ofNullable(T t)

根据传布的进参t的参数特征Optional填充取向,如果传布的t为null,则近似于初始化empty()法则,如果t不为null,则近似于初始化of(T t)法则

在工程建设以前,我们可以必需用于侧面的法则,发挥起到Optional取向的填充:

public void testCreateOptional() { // 用于Optional.of特征出具体主旨取向的填充Optional取向 System.out.println(Optional.of(new Content("111","JiaGouWuDao"))); // 用于Optional.empty特征一个不均是由任何取向的自造Optional参数 System.out.println(Optional.empty()); System.out.println(Optional.ofNullable(null)); System.out.println(Optional.ofNullable(new Content("222","JiaGouWuDao22")));}遗传物质字符串

反向结果:

Optional[Content{id='111', value='JiaGouWuDao'}]Optional.emptyOptional.emptyOptional[Content{id='222', value='JiaGouWuDao22'}]遗传物质字符串

这里所需劝注意下of法则如果传布null但会拧自造常量出现异常,所以相当决定大家用于ofNullable法则,可以相当简单初始化前的额外判自造操纵,也可以不必要无意以前激活自造常量疑问:

Optional近似于法则理解

在具体主旨提问应该如何确实用于Optional的法则前,再行来了解下Optional得到的一些法则:

法则名

意义说是明

isPresent

如果Optional实质有具体主旨取向参数,则回到true,否则回到false。

ifPresent

这是一个formula_式流程设计风格的APIAPI,进参是一个formula_,即如果Optional取向有实质取向参数,则但会可执行传布的进参formula_演算,如果不假定实质取向参数,则不但会可执行传布的进参formula_演算。

get

回到Optional填充的实质取向T样本,劝注意,如果实质取向样本不假定,但会拧出现异常而非回到null

orElse

与get法则类似于,都是得到Optional实质的取向参数,相异在于orElse只能传布一个默认参数,当Optional不曾有实质参数的时候回到默认参数而非拧出现异常

orElseGet

可以理解为orElse法则的升级版,相异在于orElse极少准许传布一个固定的默认参数,而orElseGet的进参是一个formula_法则,当Optional无实质参数时,但会可执行假定的进参formula_,回到自适应参数。

orElseThrow

与orElse类似于,相异在于如果不曾有得到到,但会拧出一个所选的出现异常。

filter

断定当前Optional的实质取向是不是完全符合进参formula_的过滤原则上,如果完全符合则回到当前Optional取向,如果不完全符合则回到自造Optional

map

转送一个进参formula_,准许将Optional以前的实质取向参数处理事件反转为另一实质取向参数(这个进参formula_的赋参数为T),并生成回到此一新各种类型的Optional取向,如果生成的一新取向为null,则回到一个自造Optional取向

flatmap

与map类似于,相异点在于进参formula_的赋参数各种类型有相异(此处进参formula_的赋参数为Optional)

看得见这里的map与flatMap法则,不见得会大家但会不但会误解到Stream引取向操纵的时候也有这两个法则的面孔呢(不了解的老师可以戳这个页面抓紧补补课:吃透JAVA的Stream引操纵)?的确,它们的起到也是类似于的,都是用来将一个取向处理事件反转为另一个取向各种类型的:

对于Optional而言,map与flatMap最终的发挥起到效用只不过都是一样的,极少极少只是进参的敦促不一样,也即两种不同读到法,两者相异点可以通过右图来理解:

实质用于的时候,可以根据所需必需用于map或者flatMap:

public void testMapAndFlatMap() { Optional userOptional = getUser(); Optional employeeOptional = userOptional.map(user -> { Employee employee = new Employee(); employee.setEmployeeName(user.getUserName()); // map与flatMap的相异点:此处return的是具体主旨取向各种类型 return employee; }); System.out.println(employeeOptional); Optional employeeOptional2 = userOptional.flatMap(user -> { Employee employee = new Employee(); employee.setEmployeeName(user.getUserName()); // map与flatMap的相异点:此处return的是具体主旨取向的Optional填充各种类型 return Optional.of(employee); }); System.out.println(employeeOptional2);}遗传物质字符串

从反向结果可以看出,两种不同的读到法,发挥起到是相同的效用:

Optional[Employee(employeeName=JiaGouWuDao)]Optional[Employee(employeeName=JiaGouWuDao)]遗传物质字符串 Optional用于过场减缓繁琐的判自造操纵

如此一来回到本篇评论最开始的那段字符串举例来说,如果我们字符串里面不去逐个想到判自造管控的话,我们可以如何来发挥起到呢?看一个大的发挥起到宽处:

public void getCompanyFromEmployeeTest() { Employee employeeDetail = getEmployee(); String companyName = Optional.ofNullable(employeeDetail) .map(employee -> employee.getTeam()) .map(team -> team.getDepartment()) .map(department -> department.getCompany()) .map(company -> company.getCompanyName()) .orElse("No Company"); System.out.println(companyName);}遗传物质字符串

再行通过map的方式则一层一层的去顺利完成各种类型反转,最后用于orElse去得到Optional以前最终处理事件后的参数,并假定了样本缺失过场的默认参数。是不是看着比一堆if判自造操纵要舒服多了?

符合过场: 所需通过某个相当宽的初始化链路一层一层去初始化得到某个参数的时候,用于上述法则,可以不必要自造常量以及减缓冗宽的假定演算。

所需有参数兜底的样本得到过场

UTF-的时候,经常但会察觉到一些样本得到的过场,所需再行通过一些处理事件演算想法得到一个样本,如果不曾有得到到所需的样本,还所需回到一个默认参数,或者是可执行另一处理事件演算继续想法得到。

比如从恳劝头以前得到客户末端IP的演算,按照这两项演算,字符串但会读到成一个大这样:

public String getClientIp(HttpServletrequest request) { String clientIp = request.getHeader("X-Forwarded-For"); if (!StringUtils.isEmpty(clientIp)) { return clientIp; } clientIp = request.getHeader("X-Real-IP"); return clientIp;}遗传物质字符串

但是来使Optional来发挥起到,可以这样读到:

public String getClientIp2(HttpServletRequest request) { String clientIp = request.getHeader("X-Forwarded-For"); return Optional.ofNullable(clientIp).orElseGet(() -> request.getHeader("X-Real-IP"));}遗传物质字符串

符合过场: 优再行可执行某个操纵想法得到样本,如果不曾得到到则去可执行另一演算得到,或者回到默认参数的过场。

替代意味著为null的法则赋参数

一个大是一段从工程建设字符串以前截取的片段:

public FileInfo queryOssFileInfo(String fileId) { FileEntity entity = fileRepository.findByIdAndStatus(fileId, 0); if (entity != null) { return new FileInfo(entity.getName(), entity.getFilePath(), false); } FileHistoryEntity hisEntity = fileHisRepository.findByIdAndStatus(fileId, 0); if (hisEntity != null) { return new FileInfo(hisEntity.getName(), hisEntity.getFilePath(), true); } return null;}遗传物质字符串

可以看得见最终的return分支以前,有一种意味著但会回到null,这个法则作为工程建设以前被高频初始化的一个法则,显然所有的初始化末端都只能要想到判自造管控。可以用于Optional顺利完成优化处理事件:

public Optional queryOssFileInfo(String fileId) { FileEntity entity = fileRepository.findByIdAndStatus(fileId, 0); if (entity != null) { return Optional.ofNullable(new FileInfo(entity.getName(), entity.getFilePath(), false)); } FileHistoryEntity hisEntity = fileHisRepository.findByIdAndStatus(fileId, 0); if (hisEntity != null) { return Optional.ofNullable(new FileInfo(hisEntity.getName(), hisEntity.getFilePath(), true)); } return Optional.empty();}遗传物质字符串

这样的话,就可以恰当的可不必要初始化末端抬起雷啦~

符合过场: 发挥起到某个法则的时候,如果法则的赋参数意味著但会为null,则考量将法则的赋参数改为Optional各种类型,原再行回到null的过场,用于Optional.empty()替代。

成品样本本体以前非只能上标符

首再行完全一致一下,Optional的意思是可选的,也即用于上标下某个属性可有可无的物理性质。啥叫可有可无?看一个大字符串:

public class PostDetail { private String title; private User postUser; private String content; private Optional lastModifyTime = Optional.empty(); private Optional attachment = Optional.empty();}遗传物质字符串

侧面是一个贴吧详情样本类,对于一个高峰但会贴吧样本而言,贴吧的标题、主旨、发帖人这些都是归属于只能的上标符,而贴吧的重读到短时间、贴吧的附件只不过是归属于可选上标符(因为不是所有的贴吧都但会被重读到、也不是所有贴吧都但会只见附件),所以针对这种可有可无的上标符,就可以书面声明假定的时候用于Optional顺利完成填充。

用于Optional顺利完成填充再次有两个非常大的劣势:

强烈的经营范围属性说是明,完全一致的让人知晓这个是一个可选上标符,近似于样本托建表表达式里面所设nullable上标一样的效用;初始化末端用于的时候也相当简单了判自造操纵。

符合过场: 样本本体假定的时候,对于可选参数,选用Optional填充各种类型替代。

用于拧出现异常替代return null

相比于回到一个Optional填充的取向,实际上拧出现异常具备强烈的----意味,意欲表达此处假定预期之外的不恰当情形,敦促UTF-的时候,初始化末端只能要予以专门处理事件。

public Team getTeamInfo() throws TestException { Employee employee = getEmployee(); Team team = employee.getTeam(); if (team == null) { throw new TestException("team is missing"); } return team;}遗传物质字符串

相比实际上return null,显然拧出现异常的意义不够加完全一致。

JDK与自由软件前提的出发点

JDK得到的很多法则里面,只不过都是遵循着本文以前描述的这种赋参数处理事件宽处的,很少但会看得见实际上回到null的——好比JDK,很多大型的自由软件前提源码以前,也很少但会看得见实际上return null的情形。

比如com.sun.jmx.Snmp.agent以前的一段字符串:

public SnmpMibSubRequest nextElement() throws NoSuchElementException { if (iter == 0) { if (handler.sublist != null) { iter++; return hlist.getSubRequest(handler); } } iter ++; if (iter> size) throw new NoSuchElementException(); SnmpMibSubRequest result = hlist.getSubRequest(handler,entry); entry++; return result;}遗传物质字符串

如此一来比如Spring以前org.springframework.data.jpa.repository.support包一个大的法则举例来说:

public Optional findById(ID id) { Assert.notNull(id, ID_MUST_NOT_BE_NULL); Class domainType = getDomainClass(); if (metadata == null) { return Optional.ofNullable(em.find(domainType, id)); } LockModeType type = metadata.getLockModeType(); Map hints = getQueryHints().withFetchGraphs(em).asMap(); return Optional.ofNullable(type == null ? em.find(domainType, id, hints) : em.find(domainType, id, type, hints));}遗传物质字符串 ja 不必要出现NullPointerException(自造常量)的法则阐释

Ja应用以前拧出的自造常量出现异常是解决自造常量的不错方式则,也是读到出能顺利工作的健壮流程的极其重要。不来是“预防措施助于治疗”,对于这么令人讨厌的自造常量出现异常,这句话也是组建的。参数得庆幸的是借助一些防御性的UTF-高难度,应用以前多个部分之间的联系,你可以将Ja以前的自造常量出现异常控制在一个很好的水平上。悄悄说是一句,这是Jarevisited上的第二个自造常量出现异常的贴吧。在上个贴吧以前我们提问了Ja以前造成自造常量出现异常的常见原因,而在本基本知识以前我们将但会进修一些Ja的流程设计高难度和最佳出发点。这些高难度可以努力你不必要Ja以前的自造常量出现异常。依从这些高难度同样可以减缓Ja字符串以前街上都有的非自造核对的数量。作为一个有经验的Ja计算机流程,你意味著如今一定会其以前的一部分高难度并且应用在你的工程建设以前。但对于一初学者和以前级研发人员来说是,这将是很参数得进修的。悄悄说是一句,如果你一定会其它的不必要自造常量出现异常和减缓自造常量核对的Ja高难度,劝和我们透过。

这些都是简单的高难度,很容易应用,但是对字符串能量密度和健壮性有非常大影响。根据我的经验,只有第一个高难度可以非常大优化字符串能量密度。如我以前所说什么,如果你一定会任何不必要自造常量出现异常和减缓自造常量核对的Ja高难度,你可以通过评论本文来和透过。

1) 从已明确的String取向以前初始化equals()和equalsIgnoreCase()法则,而非推断出取向。

却是从已明确的非自造String取向以前初始化equals()法则。因为equals()法则是梯形的,初始化a.equals(b)和初始化b.equals(a)是十分相似的,这也是为什么计算机流程对于取向a和b这么不上恨。如果初始化者是自造常量,这种初始化意味著造成一个自造常量出现异常

Object unknownObject = null;//缺失方式则 ? 意味著造成 NullPointerExceptionif(unknownObject.equals("knownObject")){ System.err.println("This may result in NullPointerException if unknownObject is null");}//确实方式则 - 即便 unknownObject是null也能不必要NullPointerExceptionif("knownObject".equals(unknownObject)){ System.err.println("better coding oided NullPointerException");}

这是不必要自造常量出现异常最简单的Ja高难度,但能够造成不够大的基础上,因为equals()是一个常见法则。

2) 当valueOf()和toString()回到相同的结果时,宁愿用于前者。

因为初始化null取向的toString()但会拧出自造常量出现异常,如果我们能够用于valueOf()获得相同的参数,那宁愿用于valueOf(),传送一个null给valueOf()将但会回到“null”,尤其是在那些成品类,像Integer、Float、Double和BigDecimal。

BigDecimal bd = getPrice();System.out.println(String.valueOf(bd)); //不但会拧出自造常量出现异常System.out.println(bd.toString()); //拧出 "Exception in thread "main" ja.lang.NullPointerException"

3) 用于null公共安全的法则和托 有很多自由软件托如今为您想到了繁重的自造常量核对工作。其以前最近似于的一个的是Apache commons 以前的StringUtils。你可以用于StringUtils.isBlank(),isNumeric(),isWhiteSpace()以及其他的工具法则而不能担恨自造常量出现异常。

//StringUtils法则是自造常量公共安全的,他们不但会拧出自造常量出现异常System.out.println(StringUtils.isEmpty(null));System.out.println(StringUtils.isBlank(null));System.out.println(StringUtils.isNumeric(null));System.out.println(StringUtils.isAllUpperCase(null));Output:truetruefalsefalse

但是在想到出正确性以前,不要忘了阅读自造常量法则的类的应用流程。这是另一个不所需下大功夫就能得到很大基础上的Ja最佳出发点。

4) 不必要从法则以前回到自造常量,而是回到自造collection或者自造数据类型。

这个Ja最佳出发点或高难度由Joshua Bloch在他的书Effective Ja以前说什么到。这是另外一个可以能够的用于Ja流程设计的高难度。通过回到一个自造collection或者自造数据类型,你可以适当在初始化如size(),length()的时候不但会因为自造常量出现异常亡溃。Collections类得到了不方便的自造List,Set和Map: Collections.EMPTY_LIST,Collections.EMPTY_SET,Collections.EMPTY_MAP。这里是实例。

public List getOrders(Customer customer){ List result = Collections.EMPTY_LIST; return result;}

你同样可以用于Collections.EMPTY_SET和Collections.EMPTY_MAP来代替自造常量。

5) 用于annotation@NotNull 和 @Nullable

在读到流程的时候你可以假定是不是可为自造常量。通过用于像@NotNull和@Nullable之类的annotation来书面声明一个法则是不是是自造常量公共安全的。现代的编译机、IDE或者工具可以读此annotation并找来你填充忘了的自造常量核对,或者向你提示出但会的于是就的自造常量核对。IntelliJ和findbugs如今赞同了这些annotation。这些annotation同样是JSR 305的一部分,但即便IDE或工具以前不曾有,这个annotation本身可以作为应用流程。看得见@NotNull和@Nullable,计算机流程自己可以决定是不是想到自造常量核对。悄悄说是一句,这个高难度对Ja计算机流程来说是相对相当一新,要选用所需一段短时间。

6) 不必要你的字符串以前但会的自动成品和自动解包。

且不管其他如创建临时取向的在技术上,如果wrapper类取向是null,自动成品同样容易造成自造常量出现异常。例如如果person取向不曾有传呼机的话但会回到null,如下字符串但会因为自造常量出现异常亡溃。

Person ram = new Person("ram");int phone = ram.getPhone();

当用于自动成品和自动解包的时候,不极少极少是等号,<> 同样但会拧出自造常量出现异常。你可以通过这篇评论来进修不够多的Ja以前的自动成品和拆包的陷阱。

7) 依从Contract并假定恰当的默认参数。

在Ja以前不必要自造常量出现异常的一个不错的法则是简单的假定contract并依从它们。多数自造常量出现异常的出现是因为用于不清晰的个人信息创建取向或者未得到所有的依赖于项。如果你不准许创建不清晰的取向并华丽地拒绝这些恳劝,你可以在月里的指导工作预防措施大量的自造常量出现异常。类似于的,如果取向准许创建,你所需给他们假定一个恰当的默认参数。例如一个Employee取向不能在创建的时候不曾有id和name,但是是不是有传呼机是可选的。如今如果Employee不曾有传呼机,你可以回到一个默认参数(例如0)来代替回到null。但是只能谨慎必需,哟一般来说核对自造常量比初始化拒绝做号码要不方便。同样的,通过假定什么可以是null,什么不能为null,初始化者可以这两项明智的决定。failing fast或做null同样是一个你所需顺利完成必需并坚持的,极其重要的设计对政府

8)假定样本托以前的上标符是不是可为自造。

如果你在用于样本托来保存你的域名取向,如Customers,Orders 等,你所需在样本托本身假定是不是为自造的约束。因为样本托但会从很多字符串以前得到样本,样本托以前有是不是为自造的核对可以适当你的样本健全。在样本自造以前控管null约束同样可以努力你减缓Ja字符串以前的自造常量核对。当从样本托以前初始化一个取向是你但会完全一致,哪些上标符是可以为null的,而哪些不能,这可以使你字符串以前但会的!= null核对总和化。

9) 用于自造取向的系统(Null Object Pattern)

还有一种法则来不必要Ja以前的自造常量出现异常。如果一个法则回到取向,在初始化者以前可执行一些操纵,例如Collection.iterator()法则回到迭代机,其初始化者可执行重构。假设如果一个初始化者并不曾有任何迭代机,其可以回到自造取向(Null object)而非null。自造取向是一个类似于于的取向,其在不同的上下文以前有不同的意义。例如一个自造的迭代机初始化hasNext()回到false时,可以是一个自造取向。同样的在回到Container和Collection各种类型法则的举例来说以前,自造取向可以被用来代替null作为赋参数。我打算另读到一篇评论来说什么自造取向的系统,透过几个Ja自造取向的举例来说。

这就是全部了,这是几个易于依从的不必要自造常量出现异常的Ja高难度和最佳出发点。你可以欣赏到这些高难度将相当简便,且不太难发挥起到。如果你有其他比秒这个出现异常的高难度,而又不曾值得劝注意欲这里,劝通过评论来和我们透过,我将翻唱在这里。

如有疑问劝网志或者到本站社区交引提问,感恩阅读,期望能努力到大家,总有一天大家对本站的赞同!

阐释

好啦,关于UTF-以前对null的一些补救处理事件战略与宽处呢,这里就给大家透过到这里,期望可以对大家相当程度启发,通过不断的显然优化与基础上,最终摆脱被自造常量摆布的局面~

那么,对侧面说什么到的一些主旨与过场,你是不是也有察觉到相关的情形呢?你是怎么处理事件的呢?欢迎多求教交引下~

江中多维元素片可以长期吃吗
益生菌与肠炎宁颗粒的区别是什么,这些要点得记住
上火喉咙痛咳嗽吃什么药
蒙脱石散和肠炎宁区别
思密达和肠炎宁哪个效果好
TAG:时候
友情链接: