今天先将剩下的一部分Java知识点汇总一下,先告一段落。后续的知识点汇总将以系列的方式进行。
13. getRequestedSessionId() vs getSession().getId()
结论
由于这个是定性的内容所以直接上结论。
HttpServletRequest.getRequestedSessionId()获取的是来自于客户端的指定会话id,可能该id在cookie里面。
而HttpServletRequest.getSession().getId()方法获取的是服务器会话id,在执行getId方法时如果getSession不存在的话就创建一个。
14. 关于异常写法的个人建议
分析
在代码走查过程中发现有很多小伙伴直接采用Exception来捕获异常,要不就是写一个自定义异常处理类来捕获这些异常。不是说以上方法不行,只是希望大家优先考虑统一异常处理机制(公司框架内含),其次考虑使用Java提供的异常类来处理。
这代码经过几手之后,由于各人编写风格问题会产生出太多自定义异常类,而且存放也并不规范在代码管理上埋了个大坑。实在是“很难抓摸啊~~”
如果你不是自定义异常的那一派,那么请你使用“多异常”捕获的方式去编写异常处理,而不是直接用顶级的Exception来捕捉异常。
结论
不要直接写成:
try { // do something that might throw an UnsupportedDataTypeException or UnsupportedEncodingException} catch (Exception e) { // Noncompliant // log exception ...}如果直接使用Exception去接收异常,会造成统一抛出父级Exception,而不知道究竟是什么样的异常,很难进一步针对异常进行追查。
try { // do something} catch (UnsupportedEncodingException|UnsupportedDataTypeException|RuntimeException e) { // log exception ... }如上所示,多个异常统一catch,采用一个e代替UnsupportedEncodingException、UnsupportedDataTypeException和RuntimeException
15. BigDecimal内容转换问题
分析
在Java中使用BigDecimal时很多小伙伴都通过构造函数出实例化BigDecimal对象,但是这个构造函数的结果可能有些不可预知。
怎么个“不可预知”法?
你可能会认为new BigDecimal(0.1)后得到的是BigDecimal类型的0.1的数据,但实际上它等于0.1000000000000000055511151231257827021181583404541015625。
这是因为0.1不能完全表示为double(或者作为任何有限长度的二进制分数)。因此,传递给构造函数的值并不完全等于0.1
BigDecimal bd1 = new BigDecimal(0.01);BigDecimal bd2 = new BigDecimal("0.01");System.out.println("bd1 = " + bd1);System.out.println("bd2 = " + bd2);bd1 = 0.01000000000000000020816681711721685132943093776702880859375bd2 = 0.01结论
因此,如果真需要使用BigDecimal的构造函数去实例化,传入初始化值必须为字符串才会产出正确的结果。
16. 不要再用DateUtils.truncate
分析
原因在于使用DateUtils.truncate方法时在转换DST(夏日节约时间 Daylight Saving Time)将出现错误,而且采用Instant的转换方式比DateUtils.truncate转换更富有效率。
结论
不再使用:
public Date trunc(Date date) { return DateUtils.truncate(date, Calendar.SECOND); }替换成:
public Date trunc(Date date) { Instant instant = date.toInstant(); instant = instant.truncatedTo(ChronoUnit.SECONDS); return Date.from(instant);}所谓「夏日节约时间」Daylight Saving Time(简称D.S.T.),是指在夏天太阳升起的比较早时,将时钟拨快一小时,以提早日光的使用,在英国则称为夏令时间(Summer Time)。
17. 不要再用File.deleteOnExit
分析
因为deleteOnExit只有在JVM正常被杀死的时候执行,若直接kill的情况下是没有办法执行的。对于每个文件处理程序,与处理程序关联的内存仅在进程结束时释放。
结论
它被调用时,相当于对deleteOnExit做了一个生声明, 不会马上执行删除操作, 而是程序运行结束, JVM终止时才真正调用删除操作。即该方法是将删除的命令缓存了一下,到服务停止的时候再进行操作!
18. JavaMail附件长度超长导致附件类型无法识别问题
分析
附件名称长度超长导致名称被截取的主要原因在于操作系统层架中参数默认值为true的原因引起的。
mail.mime.splitlongparameters :true如果在代码中设置,就必须在new MimeMessage、new MimeMultipart、new MimeBodyPart 之前(一个比较靠前的位置,如果在new MimeMultipart之后添加,有可能无效)
结论
在上述位置前添加如下代码:
System.getProperties().setProperty("mail.mime.splitlongparameters", "false");这样就能够解决这个字段长度超长的问题了。效果如下:
添加前
添加后
19. CountDownLatch的countDown需要放在finally中执行
分析
使用CountDownLatch进行异步转同步操作时,每个线程退出前必须调用countDown方法。线程执行代码注意catch异常,确保countDown方法可以被执行,避免主线程无法执行至await方法,直到超时才返回结果。
结论
CountDownLatch的countDown需要放在finally中执行,能够保证countDown必须执行。代码如下:
public class CountDownExample { public void operate(CountDownLatch countDownLatch){ try{ System.out.println("business logic"); }catch (RuntimeException e){ // do something }finally { countDownLatch.countDown(); } }}