Java 开发中如何正确踩坑
为什么说一个好的员工能顶 100 个普通员工
我们的做法是,要用最好的人。我一直都认为研发本身是很有创造性的,如果人不放松,或不够聪明,都很难做得好。你要找到最好的人,一个好的工程师不是顶10个,是顶100个。所以,在核心工程师上面,大家一定要不惜血本去找,千万不要想偷懒只用培养大学生的方法去做。最好的人本身有很强的驱动力,你只要把他放到他喜欢的事情上,让他自己有玩的心态,他才能真正做出一些事情,打动他自己,才能打动别人。所以你今天看到我们很多的工程师,他自己在边玩边创新。所以,找最好的人,要给他做他喜欢和擅长的事情。研发人员千万不要去管太严,一管就“死”了。工程师很讨厌跟规章制度打交道,作汇报他都很烦,大家不要管他,让用户去管他。他做好了一个产品,用户表扬他,这个大神多牛逼。他做不好了,用户骂他,他自己赶紧去改。
再谈阿里巴巴 Java 开发手册
之前在这个手册刚发布的时候看过一遍,当时感觉真是每个开发者都应该必读的一本手册,期间还写过一篇关于日志规约的文章:《下一个项目为什么要用 SLF4J》,最近由于在总结一些我们日常开发中容易忽略的问题,可能是最低级的编码常见问题,往往这也是最最容易忽略的,所以,又重新看了一遍这个手册,好像最近它也更新到了 1.2 版本。
这个手册目的就是让我们尽可能少踩坑,杜绝踩重复的坑。我接下来就打算试着写一些“坑”出来,来看看我们如何一不留神踩坑的,以及如何用正确的姿势跳出坑。
随随便便写出 NPE
首先声明一个 User 对象,接下来所有代码可能都会用到这个对象做演示,在下面将不在赘述。很简单,不上代码,上图片:

1.自动解箱抛 NPE
代码只有一行,再简单不过了:int method() { return new User().getId(); }

踩坑姿势:包装类型为 null 时,进行自动转换为基本数据类型报错。
解决方案:返回之前进行判断与处理或者改为相同类型。
2.级联调用易产生 NPE
这段代码有点容易迷惑人,因为它进行了集合元素的 isEmpty 判断,按说不会出问题了吧。看代码:
static void method1() {
List<User> list = new ArrayList<User>();
list.add(new User());
if (!CollectionUtils.isEmpty(list)) {
for (User user : list) {
System.out.println("userid:" + user.getId().toString());
}
}
}
不废话,看运行结果:

没错,还是报错了。
踩坑姿势:其实就是尽管你在之前做了对象不为空的判断,但你并不能保证对象中的值不为空,而且这时候去级联调用就会抛 NPE 。
手册中关于 NPE 的描述:
防止 NPE 是调用者的责任。即使被调用方法返回空集合或者空对象,对调用者来说,也并非高枕无忧,必须考虑到远程调用失败、序列化失败、运行时异常等场景返回 null 的情况。
集合里的元素即使 isEmpty,取出的数据元素也可能为 null。
级联调用 obj.getA().getB().getC();一连串调用,易产生 NPE
3.关于 Equals
这是日常开发中用于相等比较使用最多的方法了吧,因为当年谁没被 == 坑过阿。现在一般我们都会这么写:user.getName().equals("mafly");

踩坑姿势: 一不小心使用了 null 值调用了 Equals 方法。
解决方案: 很简单咯,这么写:"mafly".equals(user.getName());
equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals。
4.Map 下的 NPE
Map 应该是我们开发中使用最频繁的了,最常用的可能有 HashMap、ConcurrentHashMap 这俩了,可能会一不留神写出这样的代码:

踩坑姿势: 可能我们知道 ConcurrentHashMap 的 K/V 都不能为空,但我们有时候并不知道传进来的值是否为空。
解决方案: 设置时做下检验,对它的特性正确理解及使用。
由于 HashMap 的干扰,很多人认为 ConcurrentHashMap 是可以置入 null 值,而事实上,
存储 null 值时会抛出 NPE 异常
Map 类集合 K/V 能不能存储 null 值的情况,如下表格:
| 集合类 | Key | Value | Super | 说明 |
|---|---|---|---|---|
| Hashtable | 不允许为 null | 不允许为 null | Dictionary | 线程安全 |
| ConcurrentHashMap | 不允许为 null | 不允许为 null | AbstractMap | 分段锁技术 |
| TreeMap | 不允许为 null | 允许为 null | AbstractMap | 线程不安全 |
| HashMap | 允许为 null | 允许为 null | AbstractMap | 线程不安全 |
简单聊聊常用的集合
5.foreach 遍历集合删除元素
大家应该都知道,在遍历集合时对元素进行 add/remove 操作要使用 Iterator,使用 for 循环时会报错,一定会报错吗?看代码:
public static void main(String[] args) {
List<String> a = new ArrayList<>();
a.add("1");
a.add("2");
a.add("3");
for (String temp : a) {
if ("2".equals(temp)) {
a.remove(temp);
}
}
Iterator<String> it = a.iterator();
while (it.hasNext()) {
String temp = it.next();
if ("2".equals(temp)) {
it.remove();
}
}
}
应该会报错的吧?因为在 for 循环中移出了元素,如果你运行了就会惊讶的,输出如下:

不解释其中原因了,感兴趣的可以看这篇文章:《foreach遍历list删除元素一定会报错?》。不管是不是倒数第二个元素才没问题,我们依然要注意不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator 方式(代码第二种),如果并发操作,需要对 Iterator 对象加锁。
6.Arrays.asList() 数组转换集合
这个工具类应该都用过,可以很方便的把数组转换为集合,直接看结果吧:

踩坑姿势: Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常。 asList() 的返回对象是一个 Arrays 内部类,并没有实现集合的修改方法。
解决方案: 在转换之前操作咯。还需要注意一点,在你转换后,再对数组的值进行修改时,集合也会跟着变哦(注释掉的代码)。
7. toArray() 集合转换数组
当我们需要把一个集合转换为数组时,往往会调用 toArray() 方法,如果你用的是无参的这个可以吗?

当然不可以啦!会报 ClassCastException 异常。
踩坑姿势: 直接使用 toArray() 无参方法返回值只能是 Object[]类,若强转其它类型数组将会抛异常。
解决方案: 使用 <T> T[] toArray(T[] a); 有参数这个方法,代码如下:
String[] array = new String[list.size()];
array = list.toArray(array);
8. subList 的使用
集合中的 subList 是用于来返回某一部分的视图内容的,可能我们不是很常用,但是其中有好多坑的,直接看代码:


这次我们从输出来看上面的所有关于 subList 的代码。
- 18行: 当你原始集合大小没有那么大时,毫无疑问抛异常。
- 20-21行:得到一个新的集合,我们往新集合中增加一条数据。
- 23-26行:遍历原始集合,竟然
size=2了,而且往新集合中增加的数据存在与原始集合。 - 28-31行:移除新集合中一条数据,遍历新集合。
- 33-37行:原始集合增加一条数据并遍历。
- 40-42行:遍历新集合,抛出
ConcurrentModificationException异常。
从上述代码中,我们应该可以得出如下结论:返回的新集合是靠原来的集合支持的,修改都会影响到彼此对方。在 subList 场景中,高度注意对原集合元素个数的修改,会导致子列表的遍历、增加、删除均产生异常。
先总结一下
写到这只是其中关于异常部分的一些坑吧,还有另外一些令人异常惊讶的“我的天吶”的问题,由于篇幅太长了点,感觉不能再写下去了,过两天再接着写吧。
异常真的是一个有意思的问题。
Java 开发中如何正确踩坑的更多相关文章
- Java开发中碰到的Map的坑
这属于我在开发中碰过的坑 ,容器中存放者对象,当clear()的时候,出现的奇葩问题.好了,直接看代码: package com.DataType.yinyong; import java.util. ...
- 编写高质量代码:改善Java程序的151个建议(第一章:JAVA开发中通用的方法和准则)
编写高质量代码:改善Java程序的151个建议(第一章:JAVA开发中通用的方法和准则) 目录 建议1: 不要在常量和变量中出现易混淆的字母 建议2: 莫让常量蜕变成变量 建议3: 三元操作符的类型务 ...
- 记一次SpringBoot 开发中所遇到的坑和解决方法
记一次SpringBoot 开发中所遇到的坑和解决方法 mybatis返回Integer为0,自动转型出现空指针异常 当我们使用Integer去接受数据库中表的数据,如果返回的数据中为0,那么Inte ...
- Java开发中常见的危险信号(中)
本文来源于我在InfoQ中文站原创的文章,原文地址是:http://www.infoq.com/cn/news/2013/12/common-red-flags-in-java-1 Dustin Ma ...
- java开发中遇到的问题及解决方法(持续更新)
摘自 http://blog.csdn.net/pony12/article/details/38456261 java开发中遇到的问题及解决方法(持续更新) 工作中,以C/C++开发为主,难免与其他 ...
- Java开发中常见的危险信号(上)
本文来源于我在InfoQ中文站原创的文章,原文地址是:http://www.infoq.com/cn/news/2013/12/common-red-flags-in-java-1 Dustin Ma ...
- [ 转载 ] Java开发中的23种设计模式详解(转)
Java开发中的23种设计模式详解(转) 设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类 ...
- JAVA基础(零)—— 踩坑与错误(常更)
JAVA基础(零)-- 踩坑与错误(常更) 1 坑 考虑输入为null的情况 自动转换 x/Math.pow(10,i)*Math.pow(10,i) //由于math.pow()返回double类型 ...
- paip.java 开发中web server的选择jboss resin tomcat比较..
paip.java 开发中web server的选择jboss resin tomcat比较.. 作者Attilax 艾龙, EMAIL:1466519819@qq.com 来源:attilax的专 ...
随机推荐
- List分组 用于客服对话分组场景
工作用可能会用到会话分组: Message是消息实体对象,里面有toId和fromId 指明接收方ID和发送方Id,通过组合形式"12-22-" 为map的key public M ...
- 优化Servlet:(利用反射的思想)
1.创建BaseServlet (重写父类的service方法) package com.learning.web.servlet; import java.io.IOException; impor ...
- html静态页面实现微信分享思路
微信分享网页的时候,希望分享出来的链接是标题+描述+缩略图,微信开发代码示例里已提供了方法,但只适用于动态页面.由于dedecms是生成了静态文件,其实我想使用ajax获取jssdk参数也能也能实现微 ...
- java多线程基本概述(二)——Thread的一些方法
在Thread类中有很多方法值得我们关注一下.下面选取几个进行范例: 1.1.isAlive()方法 java api 描述如下: public final boolean isAlive() Tes ...
- 【TED】如何掌握你的自由时间
[TED]如何掌握你的自由时间 生活 某天翻阅自己原来记录的有道云笔记,发现自己在学校的时候,要求自己每周看三个TED视频,并写一些看后的总结,随意翻阅了下,就发现当时做的好的一些笔记,现在一看就能想 ...
- Jmeter自动化测试工具的简单使用--HTTP测试
Jmeter自动化测试工具的简单应用 1.安装Jmeter 链接: https://pan.baidu.com/s/1mhSzU68 密码: 446z 到这里下载 1.1 jmeter 将下载好的 ...
- Objective-C 实用关键字详解1「面试、工作」看我就 🐒 了 ^_^.
在写项目 或 阅读别人的代码(一些优秀的源码)中,总能发现一些常见的关键字,随着编程经验的积累大部分还是知道是什么意思 的. 相信很多开发者跟我当初一样,只是基本的常用关键字定义属性会使用,但在关键字 ...
- 探索 vuex 2.0 以及使用 vuejs 2.0 + vuex 2.0 构建记事本应用
前言 首先说明这并不是一个教程贴,而记事本应用是网上早有的案例,对于学习 vuex 非常有帮助.我的目的是探索 vuex 2.0 ,然后使用 vue 2.0 + vuex 2.0 重写这个应用,其中最 ...
- linux基础 作业篇
1.自动部署反向代理 web nfs #!/usr/bin/python #-*- coding:utf-8 -*- #开发脚本自动部署及监控 #1.编写脚本自动部署反向代理.web.nfs: #!/ ...
- Struts2框架的基本使用
前面已经介绍过了MVC思想,Struts2是一个优秀的MVC框架,大大降低了各个层之间的耦合度,具有很好的扩展性.从本篇开始我们学习Struts2的基本用法,本篇主要包括以下内容: Stru ...