CodeReview是保证代码质量的重要手段。StevenHeidel在LinkedIn负责代码审查。在这篇文章中,他总结了常见的代码问题并提出修改建议。当我在LinkedIn工作时,很大一部分工作是做代码审查。在这个过程中,我发现了一些人容易犯的错误,所以我把错误整理出来分享给团队。第1课:出现问题时抛出异常我看到的常见模式是:ListgetSearchResults(...){try{Listresults=//makeRESTcalltosearchservicereturnresults;}catch(RemoteInvocationExceptione){returnCollections。emptyList();}}上面的方法可能是很多新手工程师的做法,但是这种模式会有问题。在我开发的移动应用程序中,这种模式导致移动应用程序出现故障。用户搜索开始后,我们后台就开始抛异常了,但是应用的API服务端并没有抛异常。因此,从应用程序的角度来看,前端会收到200个成功响应,然后在团队不知情的情况下向用户显示空白搜索结果。如果API抛出异常,我们的监控系统会第一时间发现并及时修复。很多时候,当异常被捕获时,我们倾向于返回一个空对象。Java中的空对象示例包括Optional.empty()、null和空列表。这通常发生在URL解析中。如果无法从字符串中解析出URL,与其返回null,不如问问自己:为什么URL格式无效?这是一个需要上游解决的数据问题吗?空对象不是完成此类任务的合适工具。如果发生异常行为,则应抛出异常。第2课:尽可能使用最具体的类型基本上,这个建议与字符串类型编程完全相反。我经常看到这样的代码:voiddoOperation(StringopType,Datadata);//其中opType是“insert”、“append”或“delete”,这明明应该是ananenumStringfetchWebsite(Stringurl);//whereurlis"https://google.com",thisshouldbeanURNStringparseId(Inputinput);//thereturntypeisStringbutidsareactuallyLongslike"6345789"使用最具体的类型(type)可以避免很多bug。现在的问题是:为什么好心的程序员会写出糟糕的字符串类型代码?答案在于外部世界不是强类型的。字符串来自很多不同的来源,例如:urlJSON中的查询和路径参数不支持枚举的数据库写得不好的库在上面的场景中,我们应该使用以下策略来避免问题:放在边缘程序。下面就是这样一个例子://Step1:Takeaqueryparamrepresentingacompanyname/memberidpairandparseit//example:context=Pair(linkedin,456)PaircompanyMember=parseQueryParam("context");//thisshouldthrowanexceptionifmalformed//Step2:Doallthesuffinyourapplication//MOSTifnotallofyourcodeshouldliveinthisarea//Step3:ConverttheparameterbackintoaStringattheeveryendifnecessaryStringredirectLink=serializeQueryParam("context");这种方法有很多优点。立即发现格式错误的数据;如果出现任何问题,应用程序将提前失败。数据验证一次后,就没有必要在整个应用程序中一直捕获解析异常。此外,强类型使方法签名更具描述性,我们不再需要为每个方法编写那么多的javadoc。第3课:使用Optional代替nullJava8带来的最酷的功能之一是Optional类,它表示可能存在或可能不存在的实体。只是一个简单的问题:唯一有自己缩写的例外是什么?答案是NPE或NullPointerException。它是迄今为止Java中最常见的异常,被称为十亿美元的错误(https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare)。可选允许我们从我们的程序中完全删除NPE。但是,必须以正确的方式使用它。以下是使用Optional的一些建议:我们不能在获得Optional时简单地调用它的.get()。相反,我们应该仔细考虑Optional不存在的情况,并给出一个合理的默认值;如果仍然没有合理的默认值,像.map()和.flatmap()这样的方法允许我们推迟到以后再做决定;如果外部库返回null以表示null情况,则使用Optional.ofNullable()立即包装该值。相信我,你以后会感谢自己的。空值有在程序内部“冒泡”的倾向,所以最好在源代码中阻止它们;在方法的返回类型中使用Optional。这很棒,因为我们不需要阅读javadoc来确定某个值是否不存在。附加建议:尽可能使用“Unlift”方法我们应该避免下面显示的方法://AVOID:CompletableFuturemethod(CompletableFutureparam);//PREFER:Tmethod(Sparam);//AVOID:Listmethod(Listparam);//PREFER:Tmethod(Sparam);//避免:Tmethod(Aparam1,Bparam2,Optionalparam3);//PREFER:Tmethod(Aparam1,Bparam2,Cparam3);Tmethod(Aparam1,Bparam2);//Thismethoddisclearlydoingtwothings,itshouldbettwomethods//Thesameistrueforbooleanparameters上述弃用的方法有什么共同点?也就是说,它们都使用容器对象作为参数,例如Optional、List或Task。如果返回类型是同一种容器(例如,接收Optional的参数方法返回Optional),情况会更糟。为什么?1)Promise方法(Promiseparam)不如2)A方法(Bparam)灵活。如果有Promise,我们可以通过.map函数(即promise.map(method))使用1)或2)。但是,如果只有一个B,我们可以很容易地使用2)而不是1),因此2)是更灵活的解决方案。我喜欢称其为“提升”,因为它与“提升”的常见功能工具方法完全相反。以这种方式重写可以使方法更灵活,调用者也更容易使用。