java容易忽略的问题_Java编程中最容易忽略的10个问题

Java编程中最容易忽略的10个问题-1.jpg (70.1 KB, 下载次数: 0)

2018-10-22 22:18 上传

在Java编码中,我们容易犯一些毛病,也容易疏忽一些问题,因此我们对日常编码中曾遇到的一些经典情形归纳整理成文,以共同探讨。

1. 纠结的同名

现象

很多类的命名相同(例如:常见于异常、常量、日志等类),致使在import时,有时候张冠李戴,这种毛病有时候很隐蔽。因为往往同名的类功能也类似,所以IDE不会提示warn。

解决

写完代码时,扫视下import部分,看看有没有不熟悉的。替换成正确导入后,要注意下注释是否也作相应修改。

启示

命名尽量避开重复名,特别要避开与JDK中的类重名,不然容易导入错,同时存在大量重名类,在查找时,也需要更多的辩白时间。

2. 想固然的API

现象

有时候挪用API时,会想固然的通过名字直接自信满满地挪用,致使很惊讶的一些毛病:

示例一:flag是true?

boolean flag = Boolean.getBoolean("true");可能老是false。

示例二:这是去年的今天吗(今年是2012年,不考虑闰年)?结果还是2012年:

Calendar calendar = GregorianCalendar.getInstance();calendar.roll(Calendar.DAY_OF_YEAR, -365);下面的才是去年:

calendar.add(Calendar.DAY_OF_YEAR, -365);解决体例

问自己几个问题,这个体例我很熟悉吗?有没有类似的API? 区别是什么?就示例一而言,需要区另外如下:

Boolean.valueOf(b) VS Boolean.parseBoolean(b) VS Boolean.getBoolean(b);启示

名字起的更详细点,注释更清楚点,不要不经了解、测试就想固然的用一些API,如果时间有限,用自己最为熟悉的API。

3. 有时候溢出其实不难

现象

有时候溢出其实不难,虽然不常复现:

示例一:

long x=Integer.MAX_VALUE+1;System.out.println(x);x是几多?竟然是-2147483648,明明加上1之后还是long的规模。类似的经常呈现在时间计算:

数字1×数字2×数字3… 示例二:

在检查是否为正数的参数校验中,为了避免重载,选用参数number, 于是下面代码结果小于0,也是因为溢出致使:

Number i=Long.MAX_VALUE;System.out.println(i.intValue()>0);解决

让第一个操作数是long型,例如加上L或者l(不建议小写字母l,因为和数字1太相似了);

不确按时,还是使用重载吧,即使用doubleValue(),当参数是BigDecimal参数时,也不克不及解决问题。启示

对数字运用要连结敏感:涉及数字计算就要考虑溢出;涉及除法就要考虑被除数是0;实在容纳不下了可以考虑BigDecimal之类。

4. 日志跑哪了?

现象

有时候觉得log都打了,怎么找不到?

示例一:没有stack trace!

} catch (Exception ex) { log.error(ex); }示例二:找不到log!

} catch (ConfigurationException e) { e.printStackTrace();}解决

替换成log.error(ex.getMessage(),ex);

换成普通的log4j吧,而不是System.out。启示

API界说应该避免让人出错,如果多加个重载的log.error(Exception)自然没有毛病产生在产品代码中,使用的一些体例要考虑是否有效,使e.printStackTrace()要想下终端(Console)在哪。

5. 遗忘的Volatile

现象

在DCL模式中,总是忘记加一个Volatile。

private static CacheImpl instance; //lose volatilepublic static CacheImpl getInstance() { if (instance == null) { synchronized (CacheImpl.class) { if (instance == null) { instance = new CacheImpl (); } } } return instance;}解决

毋庸置疑,加上一个吧,synchronized 锁的是一块代码(整个体例或某个代码块),包管的是这”块“代码的可见性及原子性,可是instance == null第一次判断时不再规模内的。所以可能读出的是过期的null。

启示

我们总是觉得某些低几率的事件很难产生,例如某个时间并发的可能性、某个异常抛出的可能性,所以不加控制,可是如果可以,还是依照前人的“最佳实践”来写代码吧。至少不消过多解释为啥另辟蹊径。

Java编程中最容易忽略的10个问题-2.jpg (57.43 KB, 下载次数: 0)

2018-10-22 22:18 上传

6. 不要影响彼此

现象

在释放多个IO资源时,城市抛出IOException ,于是可能为了省事如此写:

public static void inputToOutput(InputStream is, OutputStream os, boolean isClose) throws IOException { BufferedInputStream bis = new BufferedInputStream(is, 1024); BufferedOutputStream bos = new BufferedOutputStream(os, 1024); …. if (isClose) { bos.close(); bis.close(); }}假设bos关闭失败,bis还能关闭吗?固然不克不及!

解决体例

虽然抛出的是同一个异常,可是还是各自捕获各的为好。不然第一个失败,后一个面就没有机会去释放资源了。

启示

代码/模块之间可能存在依赖,要充分识别对相互的依赖。

7. 用断言取代参数校验

现象

如题所提,作为防御式编程经常使用的体例:断言,写在产品代码中做参数校验等。例如:

private void send(List< Event> eventList) { assert eventList != null;}解决

换成正常的统一的参数校验体例。因为断言默认是关闭的,所以起不起作用完全在于配置,如果采取默认配置,经历了eventList != null结果还没有起到作用,徒劳无功。

启示

有的时候,代码起不起作用,不但在于用例,还在于配置,例如断言是否启用、log级别等,要结合真实环境做有用编码。

8. 用户认知承担有时候很重

现象

先来比较三组例子,看看那些看着更顺畅?

示例一:

public void caller(int a, String b, float c, String d) { methodOne(d, z, b); methodTwo(b, c, d);}public void methodOne(String d, float z, String b) public void methodTwo(String b, float c, String d)示例二:

public boolean remove(String key, long timeout) { Future< Boolean> future = memcachedClient.delete(key);public boolean delete(String key, long timeout) { Future< Boolean> future = memcachedClient.delete(key);示例三:

public static String getDigest(String filePath, DigestAlgorithm algorithm)public static String getDigest(String filePath, DigestAlgorithm digestAlgorithm)解决

连结参数传递顺序;

remove酿成了delete,显得突兀了点, 统一表达更好;

连结表达,少缩写也会看起来流畅点。启示

在编码过程中,非论是参数的顺序还是命名都尽量统一,这样用户的认知承担会很少,不要要用户容易出错或迷惑。例如用枚举取代string从而不让用户迷惑到底传什么string, 诸如此类。

9. 忽视日志记录时机、级别

现象

存在下面两则示例:

示例一:该不该记录日志?

catch (SocketException e){ LOG.error("server error", e); throw new ConnectionException(e.getMessage(), e);}示例二:记什么级别日志?

在用户登录系统中,每次失败登录:

LOG.warn("Failed to login by "+username+");解决

移除日志记录:在遇到需要re-throw的异常时,如果每个人都依照先记录后throw的体例去措置,那么对一个毛病会记录太多的日志,所以不推荐如此做;可是如果re-throw出去的exception没有带完整的trace( 即cause),那么最好还是记录下。

如果歹意登录,那系统内部会呈现太多WARN,从而让管理员误以为是代码毛病。可以反馈用户以毛病,可是不要记录用户毛病的行为,除非想达到控制的目的。

启示

日志改不改记?记成什么级别?如何记?这些都是问题,一定要根据具体情况,需要考虑:

是用户行为毛病还是代码毛病?

记录下来的日志,能否能给他人在不造成过多的干扰前提下提供有用的信息以快速定位问题。

Java编程中最容易忽略的10个问题-3.jpg (35.46 KB, 下载次数: 0)

2018-10-22 22:18 上传

10. 忘设初始容量

现象

在JAVA中,我们经常使用Collection中的Map做Cache,可是我们经常会遗忘设置初始容量。

cache = new LRULinkedHashMap< K, V>(maxCapacity);解决

初始容量的影响有多大?拿LinkedHashMap来说,初始容量如果不设置默认是16,跨越16×LOAD_FACTOR,会resize(2 * table.length),扩大2倍:采取 Entry[] newTable = new Entry[newCapacity]; transfer(newTable),即整个数组Copy。

那么对一个需要做大容量CACHE来说,从16酿成一个很大的数量,需要做几多次数组复制可想而知。如果初始容量就设置很大,自然会减少resize, 不过可能会担忧,初始容量设置很大时,没有Cache内容仍然会占用过大体积。其实可以参考以下表格简单计算下, 初始时还没有cache内容, 每个对象仅仅是4字节引用罢了。

memory for reference fields (4 bytes each);memory for primitive fields

Java type

Bytes required

boolean

1

byte

char

2

short

int

4

float

long

8

double

启示

不可是map, 还有stringBuffer等,都有容量resize的过程,如果数据量很大,就不克不及忽视初始容量可以考虑设置下,不然不但有频繁的 resize还容易浪费容量。

在Java编程中,除上面枚举的一些容易忽视的问题,日常实践中还存在很多。相信通过不竭的总结和努力,可以将我们的程序完美显现给读者。

更多内容回复查看:

游客,如果您要查看本帖隐藏内容请回复

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值