java采坑之路

Wesley13
• 阅读 794

判断相等

字符串判断相等
        String str1 = null;        String str2 = "java金融";       // str1.equals(str2);  错误的写法        str2.equals(str1); // 常量写前面        Objects.equals(str1, str2);// 借助jdkUtil工具类        StringUtils.equals(str1,str2); // 自定义工具类
  • 字符串判断相等我们记住一定要常量写前面。

  • 借助jdk提供的util帮助类(Objects)。

  • 自定义工具类,进行判空处理。

包装类判断相等
        Integer n1 = 100;        Integer n2 = 100;        System.out.println(n1 == n2);//true        System.out.println(n1.equals(n2));//true        Integer n3 = 200;        Integer n4 = 200;        System.out.println(n3 == n4);//false        System.out.println(n3.equals(n4));//true

为什么n3== n4 是false呢?由于包装类的缓存机制。包装类的比较用equals去判断。最推荐的还是用工具类去判断。例如上面的列子如果n3=null的话n3.equals(n4)这时候就会抛出npe了。如果用工具类的话就不会存在这种情况。总之一句话判断相等如果不愿意去判空(偷懒、代码也不好看)就借助工具类。合理使用工具类可以使你的代码减少不必要的npe。

三目运算符

这个常见的坑的话就是由于自动拆箱导致的 NPE 异常。这个阿里巴巴开发手册(需要这个手册可以关注公众号回复"JAVA")说的很明白了。java采坑之路

BigDecimal

禁止使用浮点数double,float的初始化
        double d = 1.001;        float f = 1.001f;        BigDecimal bigDecimal1 = new BigDecimal(d);        BigDecimal bigDecimal2 = new BigDecimal(f);        System.out.println(bigDecimal1);        System.out.println(bigDecimal2);

输出结果

1.0009999999999998898658759571844711899757385253906251.00100004673004150390625

这个结果是不是跟我们所期望的1.001有点不一样。

float和double可以用于工程计算科学计算,他们会有精度丢失,这是由于浮点运算器的结构导致的,但是在金融领域一旦精度出现问题就意味着可能是严重的现实经济损失,所以普通的那些数值型一般不会在这个场景下使用。

所以涉及金钱的计算一定不要使用float和double。使用BigDecimal并且一定要用String来构造。 上面的列子我们可以这样来初始化 new BigDecimal("1.001")。

进行除法运算时必须要设置保留小数位
  BigDecimal a = new BigDecimal("1");        System.out.println(a.divide(new BigDecimal(3)));

输出

Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. at java.math.BigDecimal.divide(BigDecimal.java:1690) at com.workit.demo.antisper.Test.main(Test.java:11)

解决办法:使用如下两个函数设置精度

  • divide(num, scale)

  • divide(num, scale, roundingMode)

            BigDecimal a = new BigDecimal("1");        System.out.println(a.divide(new BigDecimal(3), 2,BigDecimal.ROUND_HALF_UP));

字符串分隔(别忘了转义)

        String str = "java|php|c++";        String[] split = str.split("|");        for(String s:split){            System.out.println(s);        }

输出结果

java|php|c++

结果并不是我们所期待的,java、php、c++。解决办法我们对|进行转义分割,代码改为 String[] split = str.split("\|");结果就正确了。String的split方法需要转义的字符串:. $ | ( ) [ { ^ ? * + \ 共12个特殊字符,遇到以这些字符进行分割字符串的时候,需要在这些特殊字符前加双反斜杠\ \。

Arrays.asList 需要谨慎使用

下面列举一些常用但是却与我们所期待的结果不一样的用法。

将基本类型数组作为asList的参数
   int[] array = {1,2,3};        List list = Arrays.asList(array);        System.out.println(list.size()); //1

输出的结果是1不是3哦是不是跟想象的有点不一样?原因如下: 由于Arrays.ArrayList参数为可变长泛型,而基本类型是无法泛型化的,所以它把int[] array 数组当成了一个泛型对象,所以集合中最终只有一个元素array 。

将数组作为asList参数后,修改数组或List
        String[] array = {"欢迎","关注","java金融"};        List list = Arrays.asList(array);        array[0] ="修改数组第一个元素";        list.set(2,"修改集合第三个元素");        System.out.println(Arrays.toString(array));        System.out.println(list.toString());

输出结果

[修改数组第一个元素, 关注, 修改集合第三个元素][修改数组第一个元素, 关注, 修改集合第三个元素] 

是不是也与我们所期待的不一样。修改了数组奥了的值居然影响到了集合里面的值。原因如下: 由于asList产生的集合元素是直接引用作为参数的数组,所以当外部数组或集合改变时,数组和集合会同步变化,这在平时我们编码时可能产生莫名的问题。

数组转换为集合后,进行增删元素。
         String[] array = {"欢迎","关注","java金融"};        List list = Arrays.asList(array);        list.add("java金融");        System.out.println(list.toString());

输出结果:

Exception in thread "main" java.lang.UnsupportedOperationException at java.util.AbstractList.add(AbstractList.java:148) at java.util.AbstractList.add(AbstractList.java:108)

抛出异常原因:由于asList产生的集合并没有重写add,remove等方法,所以它会调用父类AbstractList的方法,而父类的方法中抛出的却是异常信息。当我们使用Arrays.asList 产生的集合时候,需要谨慎的去使用。如果需要对集合进行操作的时候我们可以通过 List list = new ArrayList(Arrays.asList(array)); 来进行使用。

currenHaseMap注意 key和value的null值
       String key = "java金融";        Map<String,Object> map = new ConcurrentHashMap<>();        map.put("1","2");        map.put(key,null);// Exception in thread "main" java.lang.NullPointerException

记得刚开始工作的时候,我负责的一个管理系统里面有一个关于省份的缓存,用HashMap来存的。大概就是项目一起动,然后就从db里面把省份信息加载到HashMap里面,以后需要用到省份信息直接从HashMap里面取,HashMap不是线程不安全吗?然后我反手就把它改成了currenHaseMap。测试环境测试没问题,然后就跟着其他功能上线。上完线之后也没有去回归关于省份的这一块内容,然后就下班了。第二天上班运营反映有部分注册用户的省份信息没了。leader就找我昨天有没有改过关于省份的代码,我说就改了一个currenHaseMap。leader先让昨天上线代码回退,一回退省份信息就有了。后面经过仔细排查原来生产数据库有一条省份信息是空的。然后加载那条空的省份信息到currenHaseMap就报空指针了,在这条空记录后面信息就没加载到currenHaseMap了。幸好是内网管理系统没有造成太大的影响 。

string.valueof

    String  userName= String.valueOf(parmMap.get("userName"));        if(StringUtils.isNotBlank(userName)) {            sql.append(" and tt.userName like %").append(userName);        }

这里的 parmMap.get("userName") 如果是 null , 那么这里的 userName就是 “null” ,这是一个值为 null 的字符串。导致数据会拼接到SQL 中,导出出错。为什么会这样我们看下源码就知道了。

 public static String valueOf(Object obj) {        return (obj == null) ? "null" : obj.toString();    }

所以转字符串的时候我们要根据实际的情况来选择合适的方法。

总结

本文列举了一些对于java常见的一些可能稍微不注意就会采坑的一些知识点。还有其他更多需要注意的知识点也欢迎大家来补充。其实这些常见的采坑基本上只要去看下源码都能够避免的。

结束

  • 由于自己才疏学浅,难免会有纰漏,假如你发现了错误的地方,还望留言给我指出来,我会对其加以修正。

  • 如果你觉得文章还不错,你的转发、分享、赞赏、点赞、留言就是对我最大的鼓励。

  • 感谢您的阅读,十分欢迎并感谢您的关注。

  • java采坑之路

  • 我建了一个群,群里有很多大佬,欢迎大家入群探讨。

  • java采坑之路

往期回顾

超长JVM总结,面试必备

本地缓存性能之王Caffeine

ArrayList哪种遍历效率最好,你真的弄明白了吗?

有了它(powerMocker)再也不怕单元测试不达标了!

本文分享自微信公众号 - java金融(java4299)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Easter79 Easter79
3年前
string.Compare用法
string.Compare方法,用来比较2个字符串值得大小string.Compare(strA,strB,true);返回值:1:str1大于str20:str1等于str2\1:str1小于str2publicvoidCompareString(stringstrA,stringstrB)
Wesley13 Wesley13
3年前
SHELL IF条件判断,判断条件
1字符串判断str1str2      当两个串有相同内容、长度时为真str1!str2     当串str1和str2不等时为真\nstr1       当串的长度大于0时为真(串非空)\zstr1       当串的长度为0时为真(空串)str1          当串str1为非空时为真
Stella981 Stella981
3年前
HIVE 时间操作函数
日期函数UNIX时间戳转日期函数: from\_unixtime语法:   from\_unixtime(bigint unixtime\, string format\)返回值: string说明: 转化UNIX时间戳(从19700101 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式举例:hive   selec
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Docker 部署SpringBoot项目不香吗?
  公众号改版后文章乱序推荐,希望你可以点击上方“Java进阶架构师”,点击右上角,将我们设为★“星标”!这样才不会错过每日进阶架构文章呀。  !(http://dingyue.ws.126.net/2020/0920/b00fbfc7j00qgy5xy002kd200qo00hsg00it00cj.jpg)  2
Wesley13 Wesley13
3年前
VIM和sed 替换字符串方法
(1)VIM替换字符串方法1\.基本替换:s/str1/str2/替换当前行第一个str1为str2:s/str1/str2/g替换当前行所有str1为str2:n,$s/str1/str2/替换第n行开始到最后一行中每一行的第一个str1为str2:n,$s/str1/str2/g替换第n行开始到最后一行中每
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这