关于后端:这篇文章汇聚33个BUG来挑战一下看看你能找出来几个

32次阅读

共计 11235 个字符,预计需要花费 29 分钟才能阅读完成。

你好呀,我是歪歪。

前几天看到“Qunar 技术沙龙”公众号推送了一篇对于他们举办了一场“Code Review 大赛”的文章。

看到 Code Review 我很感兴趣啊,“啪”的一下就点进去了啊,很快啊。

难能可贵的是,“Qunar 技术沙龙”本着凋谢共享准则,把他们的 CR 大赛真题进行了收费凋谢。

我过后“啪”的一下就先把真题拿到手了,而后对着真题“刷刷刷”就是一顿输入。

不得不说,这套题出的是真的很不错,所以写篇文章带大家感触一波。

然而我感觉为了让你有更好的体验,我强烈建议你先在拿到这套真题,本人做一遍,而后在来和我对一下答案。

那么问题就来了:怎么拿到真题呢?

在公众号 ”why 技术 ” 后盾回复关键字“CR”即可拿到。

如果你还是感觉麻烦,那么你也能够点开上面这张图片,而后往右边滑动,这样你就能够先只看到题目,而不看我的解析,(然而有可能忽然看到一些奇怪的图片),能够本人先在心里做一遍。

还得提前阐明一下的是,我写文章的时候,官网并没有给出每道题的标准答案是什么,官网题解也只是出了七道,前面还会缓缓做进去,所以我给出的解析也不肯定是全副正确的。

还有,我能揭示你的是,一个题目外面可能有多个问题点,你须要尽量多的辨认进去,宁肯错杀,不可放过。

因为官网还未齐全颁布正确答案,那这样就更加有意思了,因为当你发现你的答案和我的答案不一样的时候,就是咱们互相学习的时候。我特地心愿你能斧正我的答案,也特别感谢你能在评论区分享你的、和我不一样的答案。

咱们碰撞一下,共同进步。

另外,官网题解在这里:

《看 ChatGpt 解去哪儿网第四届 CR 大赛题目》

目前只解答了 7 道题目,前面的解答还在路上。然而官网的题解中整了个活儿,就是把整段代码喂给 ChatGPT 让它帮忙诊断有什么问题,能够去看看。

我只能用一个字来形容它:

第 1 题

首先,拿到这题第一眼,我就看到一个十分顺当的中央,办法入参:cazeList?

不应该是 caseList 吗?

其实我了解 core review 不只是应该关注业务逻辑,也应该关注到这些命名标准、变量拼写的“小中央”。

所以,秉着宁肯错杀,不可放过的准则,这算是一个须要批改的点。

而后第二个点:入参不判断非空的吗?

你看第 9 行,拿着 caseList 这个入参就在开始 get(0) 了。caseList 是传入进来的,万一传了一个 null 怎么办?

不要给我说里面可能判断了,不会传递 null。不要基于假如去剖析问题,再次强调:宁肯错杀,不可放过。

在这里加上一个非空判断,代码的健壮性更强。

接着看代码,在第 9 行做了一个批量插入的动作。被 try-catch 代码块包裹了起来。

在 catch 代码块外面执行了表不存在则创立,而后再插入的动作。这个代码能用,然而我集体感觉:不要在 catch 代码块外面写过多的逻辑,也就是尽量不要基于异样去做程序逻辑管制。

在插入之前先执行创立表的动作,而后再执行批量插入,这样的正向逻辑它不香吗?

总结一下第一题:

  1. 入参名字拼写错误,cazeList 应该是 caseList。
  2. caseList 没有做非空测验。
  3. 应该把 catch 代码块里创立表的动作,放到 try 逻辑外面去。先尝试创立表,再批量插入。

第 2 题

这题没啥好说的,间接秒杀。

五秒之内没有看出问题,阐明“八股文”背的不牢。

我问你:Spring 事务注解失效的前提是什么?

是不是事务办法的调用方得是通过 Spring 代理后的对象?

那么下面代码中的事务会失效吗?

必定不会的。

经典的 this 调用导致事务注解生效的场景,一眼秒杀之。

第 3 题

这题也应该属于能够“秒杀”的题目。

你看一下 getInstance 办法的实现,这是什么老伙计?

这不就是咱们可恶的基于双重锁查看实现的单例模式吗?

当面试官问你双重锁查看的时候,考点是什么?

第一个看锁对象,这里是 class 对象,全局一把锁,没故障。

第二个问你为什么要判断两次 instance == null。

因为有可能 A,B 两个线程都执行到了 16 行去抢锁。这个时候 A 先抢到了,B 就被阻塞。A 线程创立完一个实例之后开释了锁,这个时候 B 继续执行,如果不再次判断 instance == null,那么就会再次执行初始化的动作。

第三个考察点 instance 为什么要加 volatile?

因为一个对象的创立是分为三步的:

  1. 调配对象的内存空间
  2. 初始化对象
  3. 设置 instance 指向刚调配的内存地址

如果 2 和 3 步被重排序了,那么就会呈现一个有内存地址,然而还没有初始化实现的对象。

如果这个对象被其余线程拜访到了,那么就是有问题的。所以咱们加一个 volatile 来就禁止指令重排序,来躲避这个问题。

这些都是老八股了,就不细说了。

拿着刚刚说的三个点,去和题目外面的代码比照,就会发现题目外面的代码是没有加 volatile,所以这就是要修复的中央。

另外,多说一句。加 volatile 这个计划,得 JDK5 版本以上应用,因为在 JDK5 之后,应用的新的 JSR-133 内存模型标准,在这个标准外面加强了 volatile 的语义。

该死,这句话是怎么呈现在我的脑子外面的?

它就像是忽然蹦出的一样,这就是传说中的刻在基因外面的“八股文”吧。

第 4 题

这题第一个非常明显的优化点在第 20 行。

要是看到这句话之后你还没反馈过去是咋回事,那完犊子了,多半是要回去等告诉了。

对于“流”的操作,敞开流的代码必须放在 finally 代码块外面啊,或者用 try-with-resource 语法糖,这是晚期学 JavaSE 的时候就要重点把握的货色了。

第二个要一眼秒杀的优化点是 22 行。

谁教你这样打印日志的?这样打印能够说齐全没有任何卵用啊,因为失落了“故事现场”。

应该这样写:

log.error(“ 出现异常啦 ”,e);

保留整个异样堆栈,不便后续定位问题,

第三个问题是 fileName,文件名称用的是工夫戳,这样是有并发危险的。尽管看形容,这是一个给经营人员应用的性能,没啥并发量。在这个场景下,属于“错杀”。

然而,“并发”这根弦还是应该绷紧的。万一是内部客户导出性能呢?万一内部客户很多呢?万一很多内部客户就是在同一时间发动了统计呢?

第四个问题是我没搞懂第 11 行外面在干啥,因为题目中没有给出这部分的代码。

我了解应该是一个从某个数据源依据指定参数查问数据的性能。

为什么要把数据查出来之后再和 TOP_CAPCITY 比拟并截取 list 呢?

如果运营商很多,比方有 10w 个运营商,然而经营只想看前 10 的运营商,也就是 TOP_CAPCITY=10 的状况。

这样把 10w 个运营商查问进去齐全没有意义,而且还容易产生大对象,对 GC 也不敌对啊。

所以,为什么不在查问数据源的时候,把 TOP_CAPCITY 作为参数传进去呢?

我认为这是第四个优化点。

总结一下第四题:

  1. 输入流敞开未放到 finally 代码块,或者用 try-with-resource。
  2. 日志打印不标准。
  3. 文件名称用的是工夫戳,有并发危险。
  4. 查问数据的时候应该把 TOP_CAPCITY 作为条件,而不是全副查问进去再截取。

第 5 题

针对 future 进行异样捕捉的时候,只捕捉了 ExecutionException 异样。我感觉至多还得捕捉一个 TimeoutException 吧。

因为这个 future 是 dubbo 接口异步获取的,所以 get 操作获取超时的场景应该还是比拟常见吧。

另外一个就是 19 行和 29 行的日子打印,我不晓得为什么没有采纳 {} 占位符的形式去做,而是采纳了 + 拼接。这个点因为 TITLE_Arg1 参数到底长啥样的,代码外面没有体现进去,所以只是提上一嘴。

然而同样是日志打印,34 行的日志打印和后面的一样,失落了“故事现场”,没有把 e 打进去。

第 6 题

这一题,我首先想到的第一个是没有对 redPlanIdList 对象进行非空判断。

而后一看 Safes.of 这是什么写法,没见过啊。

于是用关键字搜寻了一把:

相干的后果很少很少,只有看到这个靠谱一点:

这是他人本人封装的一个办法,并不是什么组件外面的。

好吧,就权且当这个办法是对 null 对象进行了解决吧,把 null 转化为了空集合,防止了空指针异样。

而后咱们接着往下看,在第 7 行应用了 parallelStream,并行流来对 redPlanIdList 对象进行操作。

然而你看一下第五行,咱们晓得 redPlanIdList 这个对象是一个 List,然而它具体是什么 List 呢,是 ArrayList 还是 CopyOnWriteArrayList 呢?

不得而知。

那咱们假如是非线程平安的 ArrayList 呢?

有的同学看到这里的时候,是不是要开始抢答了:这题我会,在多线程外面应用了 ArrayList,有线程平安问题 …

不对啊,抢答的不对啊。

即便这个中央的 redPlanIdList 是非线程平安的 ArrayList 也没有关系。因为在并行流外面,只是遍历了它,并没有对它进行新增操作。

所以 redPlanIdList 并没有线程平安问题。

有问题的是 15 行,result 是 ArrayList,调用了 addAll 办法,有线程平安问题。须要应用线程平安的汇合类。

或者,把 parallelStream 批改为单线程的 stream,对吧?

对吗?

从程序逻辑上讲是对的,应用单线程没有任何故障。

然而从需要背景上讲,这个中央完完全全就能够、也应该应用多线程的形式去晋升响应速度嘛。

所以,总结一下这题:在多线程外面调用了 arrayList 的 addAll 办法,有线程平安问题。须要应用线程平安的汇合类。

另外,诘问一个八股文:请问 ArrayList 的线程不平安具体体现在什么中央?

针对这个问题,早年间,我还写过相干的文章,如果你不分明的话,能够去翻翻:《ArrayList 的线程不平安》

这里就间接说答案了。

ArrayList 的线程不安整体当初多线程调用 add 办法的时候。具体有两个体现:

  1. 当在须要进行数组扩容的临界点时,如果有两个线程同时来进行插入,可能会导致数组下标越界异样。
  2. 因为往数组中增加元素不是原子操作,所以可能会导致元素笼罩的状况产生。

第 7 题

这题,我靠,第一眼,不得秒了它?

遍历 ArrayList 的同时,还在调用它的 remove(int index) 办法。这写法,江湖大忌啊。

在这个题目外面,因为调用了 remove(int index) 办法,所以导致队列的长度在变动,因而第 7 行会抛出数组下标越界的异样:

此外,如果把题目中的 for 循环批改为这样:

for (String s : testStrArray) {testStrArray.remove(s);
}

也是要完犊子的写法,会抛出 ConcurrentModificationException,老八股了,不细说了。

牢记一句话:针对 ArrayList 的删除,用迭代器来实现,稳得一笔。

除了这个不言而喻的问题之外,在下面的题目中还有一处能够优化的中央。

就是 emp、empany、q、t 这几个变量名字取的真丑。你取名的时候,取做 isAllMatch、isAnyMatch、findFirstOfStr 它不香吗?

第 8 题

问题很好发现,精度失落。

改过嘛 …

为什么不问问神奇的 ChatGPT 呢?

第 9 题

这个 B…

我是说这个类名称,B,是不是有点太随便了?

当然我猜想这可能是主办方为了脱敏,轻易取了一个 B,不过这是不是有点太随便了?

而后看看第 10 行,我了解不应该把异样抛给前端吧,除非你我的项目外面有全局异样处理器,然而题目中没体现,所以也提一嘴,保平安。

接着 15 行,又是流没有敞开,后面曾经呈现过一次了,不赘述。

再看看 16 行,HashSet 这玩意也不是线程平安的啊。所以在线程池外面,多线程调用其 add 办法,得改。

另外,你这个 HastSet 对象的名称叫做 visted。

我晓得你是想表白这个 Set 外面放的是被拜访过的 url。

然而 visted,什么鬼?不应该叫做 visited 吗,老铁。

既然都说到拼写错误了,那么你在看看这个办法名:proceessLog。

解决日志,应该是 processLog 吧。

多了一个字母,有一点代码洁癖的人,看得好受。

最初,最重大的一个问题,你看看第 10 行的这个线程池:newCachedThreadPool。

这玩意的调用的线程池的构造方法是这样的:

这是一个能够一直开新线程的线程池啊,而后你再读题:在文件中有大量的 URL。

“大量”,完犊子,线程过多,性能反而拉胯。

另外,线程池提交用的是 execute 办法,应该用 try-catch 代码块把线程池外面的逻辑给包起来,在 catch 外面记录日志,省得前面出问题了,日志都找不到。

第 10 题

官网给的题目中,第 9 题和第 10 题反复了。

我大抵是病了,横竖都睡不着,坐起身来点起了一支烟,这悲伤没有由来,黯然看着背后的两套考卷,一套是我的,另一套也是我的。

我打开考卷一查,这题目没有答案,歪歪斜斜的每页上都写着“找出 BUG”四个字。我横竖睡不着,认真看了中午,才从字缝里看出字来,满本都写着两个字是:卷起来。

第 11 题

这题,读完题就得秒啊,得秒之。

都曾经说的很明确了:

  1. is 结尾的 boolean 类型的属性,用的是 FastJson 序列化。
  2. 反序列化的工具有可能是 FastJson,也有可能是 gson。

首先第一点,即便你之前不晓得 FastJson 对于 is 结尾的 boolean 类型属性的解决形式,然而你从题目上也能读出来,题目上特意写了这句话,阐明外面是有故事的。

第二个,序列化工具是 FastJson,然而反序列化可能是 FastJson 也可能是 gson。

这不就离了大谱了吗?

下面的代码我也拿进去给你跑一下,就很分明了:

FastJson 序列化的时候,把 isWmsSend 变成了 wmsSend。而后用 Gson 反序列化的时候,发现没有 isWmsSend 这个属性呀,再一看,是根本类型的 boolean,那就给默认值,false 吧。

所以 isWmsSend 应该用包装类 Boolean,尽量不应用根本类型 boolean。因为包装类的默认值是 null,根本类型的默认值是 false。

在你的业务代码中,null 和 false 代表的可齐全不是一个货色。

因为反序列化的问题导致把 true 变成了 false,这一听就是一个大锅啊,可不敢乱背。

第 12 题

看到这个题的第一眼,我的注意力是放在正文上的。

你看第 13 行到第 15 行的正文是放在代码前面的。然而第 23 行到 28 行的正文又是放在代码下面的。

这是两种不同的格调,我集体喜爱的是第二种。然而不论你喜爱哪一种,你至多对立一下吧。

还有,这里又呈现了 proccess 这个单词。后面第 9 题的时候,写的是 proceess。

我能说什么呢?

我只能单打一个:6。

我抵赖,这两个点的确有点求全责备了,然而作为有点代码洁癖的我来说,必须要说进去才爽。

而后,再说说这个代码真正有问题的中央。

第一个其实很显著,一千万的数据量,一页读取一千条数据,用传统的分页,到前面的深度分页,你会发现越来越慢,因为这个是有性能问题的。

应该采取游标的形式,比方返回本次查问的 max(id),而后下一次分页的时候带着 id 去查问。

这个也算是一个八股文吧,如果你不理解的话,去找材料背一背。

第二个问题是没有对 objectList 进行非空判断,避免空指针。

第三个问题,应该在 26 行的 for 循环外面搞个线程池,来晋升数据处理速度。你这 1000w 的数据量了,单线程得搞到什么时候啊。

可能营销流动都要完结了,用户还没收到推送。到时候流动成果不好,又是程序员背锅。

第四个问题是 35 行这个办法。尽管我不懂 UserDao 这个写法是什么意思,应该是公司外部封装的长久化框架。

然而我看到这里是把 tableName 作为参数传递到了办法外面,这个时候就得提高警惕了:同志们,谨防 SQL 注入啊。平安的那帮哥们就喜爱扫这样的代码,拿进去公示。

第 13 题

这个题很有意思啊,因为它的考点比拟多,也算比拟“偏一点”。

另外,终于把 process 写对了,难受了。

首先第一个,第 7 行加锁,第 8 行万一抛出异样了怎么办?

所以这个锁弄的有大问题啊,依照标准来说,加锁操作是要放在 try 代码块外的第一行。这之间不应该有任何其余的代码,免得加锁胜利了,然而未解锁,呈现死锁的景象。

第二个问题,很显著,你看第 15 行,processWorkB 办法有两个入参,然而第 10 行调用的时候只给了一个?

这个应该是题出的失误了,不做查究。要是有人真写出了这样的代码并没有发现问题,阐明他是个奇才。要害是这玩意,代码都编译不过啊。

第三个问题,还是 processWorkB 办法,没有对 param 参数进行非空判断。

来我问你一个问题:如果 param 是 null 会呈现什么状况?

必定是空指针异样了啊。

然而,你有没有想过一个问题:switch/case 外面为什么不做成反对 null 的模式呢?

如果表达式为 null,咱们就拿着 null 去 case 外面匹配,这样实践上做也是能够做的。

对于这个问题,我再这篇文章外面做过探讨,有趣味能够去看看:《被阿里一道根底面试题给干懵了,一气之下写出万字长文。》

第四个问题:在 processWorkA 外面,暗藏的比拟深,然而的确是一个我在理论编码的过程中踩到过的一个坑。

简略来说就是三目表达式外面的拆箱问题。

巧了,这个问题,我之前也提到过一次:《三目表达式的主动拆箱问题》

网上的相干解析也很多,如果不理解的话能够定向攻破一下。

具体到这个代码中的问题,就是两头的 params1*params2 之后的后果,类型是 int 型。因为三目表达式类型要对齐的个性,所以 params3 会被拆箱为 int 类型。

后果,params3 参数又是一个 null。

哦豁,空指针就来了。

第 14 题

题目太长,我切实是看的费劲儿。

就 …… 不解析了吧。

你发现了问题,能够再评论区教教我。

第 15 题

这一题,说实话,我第一眼没看进去问题。

隔了一会,第二眼看,也没看进去啥问题。

要不是这是一道题目,代表它的确有问题,不然在理论 review 的时候,我应该就放过这个局部了。

当我带着它肯定是有问题的心态去看问题的时候,终于还是发现了端倪。

第 6 行,多线程操作,个别出题人会在多线程外面埋坑,只有找出多线程外面线程不平安的操作即可。

而多线程外面的外围逻辑是给 Status 的 reason 字段赋值。再定眼一看:Status 是个枚举啊。

枚举是单例啊。

单例对象的一个字段,在多线程外面被疯狂操作 …

你明确我意思吧?

我给你搞段代码验证一下:

首先,把 List 外面的对象搞得多多的。

而后,closeStatus 办法外面打印 log 的时候,入参的 id 必定要和 Status 枚举中的 reason 这个字符串外面拼接的 id 一样,对吧?

所以,我在 log 外面打印日志的时候,判断 reason 不蕴含以后的 id。

如果有输入,则阐明有问题,能反馈过去吧?

程序跑起来,的确有输入:那就阐明的确有问题:

id:4548 以后的状态是: 敞开 变更起因为: 敞开以后状态 3370
id:796 以后的状态是: 敞开 变更起因为: 敞开以后状态 3300
id:8621 以后的状态是: 敞开 变更起因为: 敞开以后状态 8000
id:9791 以后的状态是: 敞开 变更起因为: 敞开以后状态 7528
id:8283 以后的状态是: 敞开 变更起因为: 敞开以后状态 7842

不要在多线程外面对单例对象进行批改操作,你把握不住。

第 16 题

这题,拿到手第一眼,十分刺眼的一个问题就是 SearchCategory 对象外面的属性没有被 private 润饰,不满足 Java 对于对象进行封装的思维。

第二个考察点其实也不难,第 22 行,两边都是 Integer 对象,针对封装对象的比照,应该应用 !equals 而不是 !=。

别问为什么,问就是 Integer 缓存了 -128~127 之间的数字,在这个范畴内用 == 和这个范畴外用 ==,运行后果不一样。

老八股了,不细说了。

第三个考察点,略微略微荫蔽一点:SearchCategory 没有重写 hashcode 和 equals 办法。

categorySet 是一个 Set 汇合对象。第 25 行外面,在把 SearchCategory 往 categorySet 外面放。

自定义对象往 Set 汇合外面放,如果不重写 hashcode 和 equals 办法,那么会有反复元素滴。

如果这个你一时间没反馈过去的话,那我问你一个老八股:HashMap 的 key 是自定义对象的时候,应该留神什么?

这样一听,是不是就相熟多了。

你在联合我之前写过的这篇文章:《轻轻给你说几个 HashCode 的破事。》

轻松拿下。

第 17 题

这题我没搞懂第 6 行和第 9 行,调用了 queryUserStock 办法,然而这个办法又在同一个类外面。

为什么要通过本人注入本人的形式去调用呢?

又不波及到比方事务、缓存这些切面相干的货色。所以我感觉这两行代码没用。

而后是第 4 行外面的入参 userId 是根本类型 long,而到了 14 行外面就变成了包装类型 Long。

所以,从这个代码片段来说,15 行的判断永远为 true,因为传递进来的 userId 是根本类型,默认值为 0,不可能为 null。

应该放弃类型统一,都用包装类型。

还有一个点是 11 行,对于返回的汇合没有做非空判断,万一空指针了呢,对吧?

对个毛线,我在这里虚晃一枪,看看你有没有带着本人的思考看文章。

14 行的办法是不会返回空指针的,如果没查到数据,MyBatis 会主动帮咱们封装为空集合,而不是 null。

所以里面拿到空集合也没有任何故障。

另外,再这里我再次重申一下:官网也没有给出全副的题目解析,所以我给的答案不肯定是正确的,你要带着批评的眼光来看。

我等着你发现错误,斧正我呢。

第 18 题

题目做到这里后,一看到多线程,就开始条件反射式的想到了线程平安问题。

定眼一看,33 行,CopyOnWriteArrayList 是线程平安的,看来这次的考察点不一样了。

从上往下看,首先是自定义线程池,我一眼就看出了问题:

(r, executor) -> log.error(“…”)

自定义回绝策略中,仅仅打印了一行日志,没有做其余任何操作,有坑,容易喜提生产事件:

详情见连贯:《尽管是我遇到的一个辣手的生产问题,然而我写进去之后,就是你的了。》

所以这个回绝策略须要从新写一个。

第二个问题:21 行调用了 filter 办法,在这个办法外面用到了线程池,然而你仔细分析一下 34 行的这个 for 循环,要循环多少次?

是不是要循环“一页的大小”,也就是第 19 行的 500 次。然而这个线程池的容量才多少?

这个线程池同工夫做多也只能包容 120 个工作,所以这个中央参数不合理,须要调整线程池参数。

另外,34 行这个循环对象也没有判空啊。这是一个 JSONObject 对象,一不留神,取出一个 null 怎么办?

第三个问题,35 行,用了 submit 提交工作,这个办法是有返回值的,然而代码外面又没有应用这个返回值,那么为什么不必 execute 办法呢?

第四个问题,47 行,await 办法没有指定等待时间,容易死等。

比方就这个代码,线程池满了之后,并不会执行 countDown 办法,喜提一个永远在阻塞的线程。

这题靠多线程,算是撞我枪口上了,秒了,再见。

第 19 题

这题没啥特地好说的,第 18 行 repaceFirst 的第一个入参是正则表达式。

所以,如果供应商的名字外面有一些什么 *?.| 这些玩意,就会呈现问题。

其实 Sting 的一些对于内容替换的办法外面好多都是反对正则的,所以如果你不分明这个“坑”的话,那前面须要留神一下了。

这个题就不多说了,写个案例,高深莫测:

别问我为什么一眼就看到了 repaceFirst,因为我在它身上吃过亏。还有 split,这个“坑爹”的办法,也是一样,有正则坑。

第 20 题

这题 …

恕我学艺不精,的确没发现有什么问题啊?

难道是 13 行这个 false?它代表用 JDK 的动静代理,要实现接口,然而这个代码也的确实现了接口呀?

肉眼没看进去,我把代码放到本人的 idea 外面去跑也是能失常跑的:

如果这题在 AOP 上有考点的话,而且我感觉必定是有考点的,我的确拿不到这个分。

如果考的是不要把 http 接口写在我的项目启动类上的这种编码构造上的标准的话。好吧,只能说考查角度刁钻。

不晓得你有没有看出啥问题,能够在评论区教教我。

第 21 题

只有几行代码,秒之。

第 7、8 行,用 redis 加锁,set 办法和给值设置过期工夫的办法非原子性,如果 set 实现之后,expire 无奈执行, 会呈现死锁。

第 11 行,捕捉异样后没有通过日志打印异样具体的信息,不不便追溯问题。

第 22 题

其实题目做到这里的时候,都曾经有点掉入思维陷阱外面了。

啥意思呢。

比方这个题,我只是瞟了一眼,我就晓得 34 行的这个办法外面必定是有问题的。

因为如果没有问题,依照出题人的习惯,这个办法的实现会略去。

所以,当我带着这个想法去看这部分代码的时候,getCerts 之后间接调用了 get(0),不必判断汇合对象是否为空吗?

然而,你留神啊,其实在 23 行的时候判断了。

所以这个中央其实不是空指针的问题。

我感觉应该是须要联合到业务场景来看的,certs 是一个汇合,外面放的是伺机人的证件,一个人可能有多个证件,比方身份证、护照、工牌、打工人认证、一叠坏蛋卡等等这些玩意,所以用汇合来装,和正当。

然而,get(0) 你怎么给我保障获取进去的不是坏蛋卡,而是身份证呢?

代码中都没有体现这个逻辑,所以我狐疑出题人在这里是埋坑了。

第二个问题就很显著了,你认真看看题目中的三次 stream 操作。前两次操作的都是同一个汇合,而后用后果去笼罩了 passengers 参数。

看代码,是会一点点流式操作的,然而不多,不然也不会离开写了,三次操作齐全能够合并为一个。

第 23 题

这题一看 …

代码太多,看得我眼睛充血,脑壳疼。

再一看题,依照“充血模式”开发,补全一些代码。

这玩意感觉得联合着业务来才行啊,算了,我放弃,好吧。

这题我不做了。

你来。

第 24 题

感觉问题在 21 行的这个 Lists.transform 办法上,然而我没有用过这个办法,不分明是干啥的。

于是在网上查了一圈:

简略来说就是第 24 行这个 for 循环是没有用的。你能够了解未返回的这个 addresses 仅仅是一个视图,对视图进行批改,没有任何卵用。

而后是同样没有看到对于异样的解决机制,如果没有全局异样解决机制的话,有可能会间接抛给用户不敌对的谬误揭示。

第 25 题

第 29 行,又看到事务了,又是事务不失效,就不多说了。这个事务不失效这一点的确是一大考点,肯定要把这个玩意搞的滚瓜烂熟才行。

而后是 41 行到 44 行,这是个什么神奇的写法,链式 set?没见过。

所以我感觉这个中央也是有问题的,应该是想用 Builder 模式来构建对象吧。

另外,saveData 办法外面有一些数据库操作,难免会呈现一点异常情况,在这个办法外面我没有看到对于异样的相干捕捉和解决。

最初一个点,38 行,除非你用了 MDC 链路追踪,不然这行日志没有任何意义啊,至多再加上一个订单号吧。能力一眼看进去是哪个订单号被胜利更新了。

附加题

官网的题目只公开了 25 题,然而歪歪歪徒弟也想给你出几道附加题,让你来体验一下。

我丑话说在前头:做不进去的,都是假粉丝。

再多说一句,我都说了是附加题了,这些题必定就很偏了,看着图个乐就行,真正的代码 review 留神点,还是得看后面的题目。

附加题一

请找出上面代码的问题:

《附加题一的答案》

附加题二

请找出上面代码的问题:

《附加题二的答案》

附加题三

请解释上面代码不能失常完结的起因:

《附加题三的答案》

附加题四

asyncResult 是一个 Future 对象,上面框起来的代码能够认为是无限期期待,请指出其和 future.get() 的区别:

《附加题四的答案》

附加题五

请找出上面代码的问题:

《附加题五的答案》

附加题六

请解释上面代码不能失常完结的起因:

《附加题六的答案》

附加题七

以下程序是否会抛出空指针异样,并解释为什么:

《附加题七的答案》

附加题八

请找出上面代码的问题:

《附加题八的答案》

再说一次,附加题,考点很偏,看着图个乐就行。别把本人给 PUA 了。

最初,求个赞,不过分吧?

正文完
 0