那些Java开发中遇到的问题 | 您所在的位置:网站首页 › java后端开发是什么职业 › 那些Java开发中遇到的问题 |
1. 日志打印使用占位符
1.1 占位符的作用
在日常开发中,为了方便问题定位,我们通常使用日志打印输出信息时。当程序出现了异常或者其他问题,需要通过日志来定位问题所在。 通常,我们在日志输出中会直接输出变量或者参数的值,那么在出现问题时,就更能准确地定位到关键点所在。 以下是常见的使用方式: @Slf4j public class Test2 { public static void main(String[] args) { cal(5); // cal(0) } /** * 计算100除以该数后等于多少 * @param x */ public static void cal(int x) { int result = 0; log.info("param: {}", x); //打印出相关参数 try { result = 100/x; log.info("100 div {} = {}", x, result); //输出结果 } catch (Exception e) { log.info("exception occur, exception: {}", e); } } } 复制代码 1.2 错误的使用占位符上述的代码乍看之下没有问题,但是当我们传入参数0,查看日志打印结果: 想要输出异常e时,e的信息确实打印了出来,但是占位符并没有被信息取代,这是为什么呢? 1.3 问题定位在idea中,也准确的给出了该问题的相关说明,这个错误的意思是:代码中的日志语句使用了一个占位符,但是在日志语句中并没有提供足够的参数来填充这个占位符。 咦,可是我明明提供了参数e啊,为什么没用呢? 点进源码一看,恍然大悟。 当传入的参数是异常类型时,就会直接走到日志打印逻辑,而不会进行占位符格式化处理。 1.4 正确用法 可以不设置占位符,这样错误信息依旧会输出(推荐) catch (Exception e) { log.info("exception occur", e); } 复制代码 使用e.getMessage()方法,仅把异常类型的信息输出 catch (Exception e) { log.info("exception occur, excpetion: {}", e.getMessage()); } 复制代码 1.5 总结当需要将异常信息输出到日志时,无需使用占位符 {},也能将异常信息完整打印出来。 2. finally中不要使用return 2.1 问题说明在阿里巴巴JAVA开发手册中有这么一条准则: 【强制】不要在finally块中使用return。 说明:finally块中的return返回后方法结束执行,不会再执行try块中的return语句。 复制代码以下是一个简单的代码示例: @Slf4j public class Test { public static void main(String[] args) { int result = testFinally(); log.info("result is {}", result); // 输出结果为2而不是1 } public static int testFinally() { int result = 0; // 初始化返回值变量 try { result++; return result; // 返回语句 } catch (Exception e) { log.info("exception occur.", e); } finally { // 在finally块中执行一些操作 result++; return result; // 在方法的最后返回结果 } } } 复制代码打印结果如下: 2.2 正确用法 @Slf4j public class Test { public static void main(String[] args) { int result = testFinally(); log.info("result is {}", result); } public static int testFinally() { int result = 0; // 初始化返回值变量 try { result++; } catch (Exception e) { log.info("exception occur.", e); } finally { // 做一些清理资源或执行必要的清理操作 } return result; } } 复制代码 2.3 补充说明如果在try块和catch块中都没有返回值,那么在finally块中使用return语句并不会对程序产生任何影响。在这种情况下,finally块中的代码只会执行清理资源或执行必要的清理操作的任务,而不会影响函数或方法的返回值。 但是,即使在try块和catch块中没有返回值,还是应该避免在finally块中使用return语句。因为在finally块中使用return语句可能会给其他开发人员或维护人员带来困惑,并且不符合通常的编码惯例。 因此,建议尽可能避免在finally块中使用return语句,以保持代码的清晰度和可读性。 3. matches后再find 3.1 问题说明某一天,我在进行日志匹配的时候,发现一段诡异的问题。明明我都匹配成功了,但是当我想取出关键信息时,却给我报了异常。 代码复现结果如下: public class Test2 { public static void main(String[] args) { String str = "username:aaa"; String regex = "username:(.*?)"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(str); System.out.println("matches: " + matcher.matches()); // True System.out.println("find: " + matcher.find()); //false } } 复制代码离了大谱,我明明都能匹配成功,却告诉我找不到匹配的信息? 3.2 问题定位打上断点,可以很明显的看到,执行了matches方法后,match对象的内部参数值发生了变化。 点进find方法源码,我们可以看到,find方法查到的开始位置,就是last的值。 而matches()方法会将last的值置为字符串的长度,当执行find()方法时,模式匹配是从结尾处开始查找,而不是从输入序列的开头开始查找。因此,如果在Matcher对象上先调用matches方法,再调用find方法,可能会导致find方法无法找到任何匹配项。 3.3 解决办法非常的简单,只需要使用find(0),重置查找其实位置即可。 public static void main(String[] args) { String str = "username:aaa"; String regex = "username:(.*?)"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(str); System.out.println("matches: " + matcher.matches()); //True System.out.println("find: " + matcher.find(0)); //True } 复制代码 |
CopyRight 2018-2019 实验室设备网 版权所有 |