人非圣贤,孰能无过。都说Java语言是一门简单的编程语言,基于C++演化而来,剔除了很多C++中的复杂特性,但这并不能保证Java程序员不会犯错。那么对于广大的Java程序员来说,它们最容易犯的几个错误是什么呢? 接下来就一起来看看这些错误是否也是你经常犯的!

1、重复造轮子

一个明显的错误就是Java程序员习惯性的忽略已经存在的大量的库。在你决定造一个轮子之间,我建议你试着先搜一下是否有已经存在库。例如日志方面,有logback,新log4j,网络方面,有Netty或者Akka。有一些库,已经逐步变成了标准,比如Java8中加入的Joda-Time。 下面讲述的是我上一个项目中的个人经历。有一部分用于HTML转义的代码是一个开发自己完成的。这个代码正常工作了多年,但是又一次遇到了一个用户输入,代码陷入了死循环。这个用户发现应用没有反应,又重新输入了一遍,服务器因为这个死循环挂了。如果这个开发使用已有的HTML转义工具,比如Google Guava项目提供的HtmlEscaper,这个严重的问题可能就不会出现。并且现在市面上流行的大部分的开源库,背后都有团队和社区在支持,类似这样的错误,都能够及时的被修复。

2、在Switch-Case中错误的使用break这是一个很尴尬的问题,但是仍然在实际开发中经常出现。瀑布特性在switch语句中有时会非常有用,但是必要的break关键字的缺失,有时会带来灾难性的后果。比如在下面的代码中,如果在case 0中忘记放一个break关键字,代码会继续向下执行,就会在Zero之后再输出一个One: public static void switchCasePrimer() { int caseIndex = 0; switch (caseIndex) { case 0: System.out.println("Zero"); case 1: System.out.println("One"); break; case 2: System.out.println("Two"); break; default: System.out.println("Default"); } }

最好的解决办法是使用多态,并把不同的处理代码放到子类中。当然,类似这样的错误,也可以通过类似FindBugs或者PMD这样的工具检查出来。

3、忘记释放资源一旦打开一个文件,或者建立一个网络连接,一个非常重要的习惯是记得关闭资源。并且一定记得,如果在使用类似这样的资源过程中出现了错误,在异常处理中,也需要做对应的关闭操作。可能有人会说,FileInputStream对象在GC的时候,Java终结器(finalizer)会自动调用其close()方法,但是我们知道,我们无法预知GC在什么时候开始,所以我们无法预知在执行GC之前,会有多少资源无法及时关闭。为了避免这种情况,Java7推出的try-with-resources语法,是值得每个开发使用的。 private static void printFileJava7() throws IOException { try(FileInputStream input = new FileInputStream("file.txt")) { int data = input.read(); while(data != -1){ System.out.print((char) data); data = input.read(); } } }

try-with-resources语法适用于所有实现了AutoClosable接口的类。它能保证每一个资源及时的关闭。

4、内存泄露Java使用自动内存管理,所以大部分时间,我们都不会去关心内存的分配和释放,但是,这并不意味着Java开发人员需要忽略内存。在Java应用中,内存的问题也经常出现。我们知道,对象如果没有被引用了,这个对象就会被释放,但是并不意味着,就不会出现内存泄露的问题。在Java中,造成内存泄露的原因有很多,但最容易出现的情况就是对象引用无法释放,因为GC在回收堆内存的时候,如果一个对象仍然被其他对象引用,这个对象空间是不会被回收的,举个例子,如果在类中,有一个静态字段引用到一个集合,假如我们没有手动的在使用完成这个集合之后,将他设置为null,那么这个集合及这个集合中的对象,是永远不会被回收的,因为类静态字段是不会被GC的。 比如还有一种造成内存泄露的原因,就是一组对象互相引用对方,就是我们经常说的循环引用,因为循环引用,所以GC不能确定这些互相引用的对象是否还有继续存活的必要。还有一种情况,就是使用JNI时的非堆内存泄露。 一个典型的内存泄露例子: final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);final Deque numbers = new LinkedBlockingDeque<>();final BigDecimal divisor = new BigDecimal(51);

scheduledExecutorService.scheduleAtFixedRate(() -> { BigDecimal number = numbers.peekLast(); if (number != null && number.remainder(divisor).byteValue() == 0) { System.out.println("Number: " + number); System.out.println("Deque size: " + numbers.size()); } }, 10, 10, TimeUnit.MILLISECONDS);

scheduledExecutorService.scheduleAtFixedRate(() -> {
numbers.add(new BigDecimal(System.currentTimeMillis()));
}, 10, 10, TimeUnit.MILLISECONDS);
复制代码

try { scheduledExecutorService.awaitTermination(1, TimeUnit.DAYS); } catch (InterruptedException e) { e.printStackTrace(); }

在上面的例子中,我们创建了两个定时任务。第一个定时任务,从deque中获取了最后的一个数字”numbers”并判断,如果这个数字能被51整除,则打印该数字和deque的大小。第二个定时任务,不断的向deque中添加数据。两个任务都间隔10ms执行。如果这个代码执行,你会发现,deque的大小会持续的增加,直到deque中的数据占满整个堆空间。为了阻止这种情况的发生,我们可以使用pollLast方法来代替peekLast方法,因为pollLast方法会在拿到最后一个元素之后,把这个元素从deque中移除。

5、过度产生垃圾数据过度产生垃圾数据的意思,是程序运行中大量产生短声明周期的对象。这回导致GC频繁的执行,从内存中回收空间,GC的执行是需要完成堆扫描的,这对系统的性能影响是非常大的。下面是一个小例子: String oneMillionHello = "";for (int i = 0; i < 1000000; i++) { oneMillionHello = oneMillionHello + "Hello!"; } System.out.println(oneMillionHello.substring(0, 6));

在Java中,字符串是不可变的,所以每一次循环都会创建一个新的字符串对象。为了改进这种代码,我们可以使用StringBuilder来代替: StringBuilder oneMillionHelloSB = new StringBuilder(); for (int i = 0; i < 1000000; i++) { oneMillionHelloSB.append("Hello!"); } System.out.println(oneMillionHelloSB.toString().substring(0, 6));

第二个版本的代码,在执行的时候会提高不少的性能。 本次干货分享到这里就结束啦!想要获取更多干货及免费资源,请持续关注每周的更新!跟我一起进阶打怪!

看看这5个最容易犯的Java错误,你犯了没?的更多相关文章

  1. 【转载学习前辈的经验】-- Mistakes I made (as a developer) 我(作为一名开发者)所犯过的错误

    我 2006 年开始工作,至今已经 10 年.10 年是个里程碑,我开始回顾自己曾经犯过的错误,以及我希望从同行那里得到什么类型的忠告.一切都在快速改变,10 年了,我不能确定这些秘诀是否还有用. 不 ...

  2. SQLSERVER DBA容易犯的十个错误

    SQLSERVER DBA容易犯的十个错误 翻译自:http://sqlsentry.tv/top-10-administrative-mistakes-on-sql-server/ 除了排名前十的错 ...

  3. PHP开发者常犯的MySQL错误

    PHP开发者常犯的MySQL错误   数据库是WEB大多数应用开发的基础.如果你是用PHP,那么大多数据库用的是MYSQL也是LAMP架构的重要部分. PHP看起来很简单,一个初学者也可以几个小时内就 ...

  4. 关于JDBC学习过程中的注意事项(分享自己犯过的错误,写给初学JDBC的小伙伴的八条建议)

    关于JDBC学习过程中的注意事项(分享自己犯过的错误,写给初学JDBC的小伙伴的八条建议) 前言:最近在学习JDBC,总结了几个小问题,特地分享给大家,让大家不要犯这样的错误,也希望大家养成学会总结的 ...

  5. Socket编程, 在server端read()函数调用后显示错误:Transport endpoint is not connected (犯了低级错误)

    for(;;){ socklen_t len = sizeof(client_address); connfd = accept(listenfd, (struct sockaddr *)&c ...

  6. Verilog与SystemVerilog编程陷阱:怎样避免101个常犯的编码错误

    这篇是计算机类的优质预售推荐>>>><Verilog与SystemVerilog编程陷阱:怎样避免101个常犯的编码错误> 编辑推荐 纠错式学习,从"陷阱 ...

  7. 【编写程序中经常犯的一些错误】 Python | 面向对象(一)

    [编写程序中经常犯的一些错误]Python | 面向对象(一) 在学习Python的面向对象这一部分时,经常出现以下错误: 这是错误范例,请仔细甄别: class Person: def __int_ ...

  8. Android中使用java.util.Properties犯的错

    今天尝试使用java.util.Properties来保存应用配置,然而遇到了好几个问题,对于熟悉此内容的来说可能都是猪一样的错误,但难免有像我一样的新手再次遇到,希望此文能有所帮助. 错误1 jav ...

  9. 【转】十个JavaScript中易犯的小错误,你中了几枪?

    目录 常见错误一:对于this关键词的不正确引用 常见错误二:传统编程语言的生命周期误区 常见错误三:内存泄露 常见错误四:比较运算符 常见错误五:低效的DOM操作 常见错误6:在for循环中的不正确 ...

随机推荐

  1. Codeforces1114C Trailing Loves (or L'oeufs?)

    链接:http://codeforces.com/problemset/problem/1114/C 题意:给定数字$n$和$b$,问$n!$在$b$进制下有多少后导零. 寒假好像写过这道题当时好像完 ...

  2. 14-Flutter移动电商实战-ADBanner组件的编写

    拨打电话的功能在app里也很常见,比如一般的外卖app都会有这个才做.其实Flutter本身是没给我们提供拨打电话的能力的,那我们如何来拨打电话那? 1.编写店长电话模块 这个小伙伴们一定轻车熟路了, ...

  3. Redis 高可用架构设计(转载)

    转载自:https://mp.weixin.qq.com/s?__biz=MzA3NDcyMTQyNQ==&mid=2649263292&idx=1&sn=b170390684 ...

  4. 【loj2985】【WC2019】I君的商店

    题目 交互题: 有\(n\)个物品,每个物品的价格为0或者1; 给出为1的物品的个数奇偶性k,并保证至少有一个价格为1: 每次可以询问一个集合S的另一个集合T的价值和的大小,交互库会返回>=或者 ...

  5. nRF51822 配对之device_manager_init 调用,以及保证 用户数据存储 的Flash 操作不与device manager 模块冲突

    昨天 遇到了一个烦心的问题,被老外客户怼了两句,恼火,很想发火,发现英文不够用,算了,就不跟直肠的鬼佬一般见识.说正事. 最近的一个nRF51822+MT2503 钱包防丢项目,准备接近量产了.昨天做 ...

  6. 编译失败,无法安装APK

    编译失败,无法安装APK. 把libs目录中,全部内容清空,再重新编译就可以了. 应该是有些组件有冲突的原因! -------------------------------------------- ...

  7. semantic ui要装什么才能使用

    作者:呆呆笨笨链接:https://www.zhihu.com/question/32233356/answer/196799506来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...

  8. rust 函数的使用

    fn main() { println!("Hello, world!"); another_function(2,3); let y ={ let x =3; //表达式的结尾没 ...

  9. 刷题记录:[XNUCA2019Qualifier]EasyPHP

    目录 刷题记录:[XNUCA2019Qualifier]EasyPHP 解法一 1.error_log结合log_errors自定义错误日志 2.include_path设置包含路径 3.php_va ...

  10. Sql注入基本思路

    Sql注入基本思路 利用mysql自己动手 登录 使用show databases;查看数据库,sql注入主要用到的是information_schema这个库(mysql中大小写不敏感) infor ...