人非圣贤,孰能无过。都说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. linux中如何升级Python

    一.使用wget 下载Python 安装包 我是在虚拟中当中安装的: wget http://www.python.org/ftp/python/3.7.0/Python-3.7.0.tgz 报错: ...

  2. Oracle中INSTR函数与SQL Server中CHARINDEX函数

    Oracle中INSTR函数与SQL Server中CHARINDEX函数 1.ORACLE中的INSTR INSTR函数格式:INSTR(源字符串, 目标字符串, 起始位置, 匹配序号) 说明:返回 ...

  3. SQL操作Spark SQL--BasicSQLTestt

    object BasicSQLTest { def main(args: Array[String]): Unit = { val spark = SparkSession .builder() .a ...

  4. django-用户浏览记录添加及商品详情页

    视图函数views.py # /goods/商品id class DetailView(View): '''详情页''' def get(self, request, goods_id): '''显示 ...

  5. Linear Discriminant Analysis Algorithm

    线性判别分析算法. 逻辑回归是一种分类算法,传统上仅限于两类分类问题. 如果有两个以上的类,那么线性判别分析算法是首选的线性分类技术.LDA的表示非常直接.它包括数据的统计属性,为每个类计算.对于单个 ...

  6. Clickhouse 性能瓶颈排查 IO过高

    前几天公司clickhouse 有个查询很慢.经理一直追问为什么慢 是cpu 不够 还是IO 占用太高,还是其他的原因.于是有了以下的排查 执行该条,在不考虑优化sql 的情况下 进行性能排查 1.首 ...

  7. 如何用okr做好目标规划

    有朋友和我吐槽公司总是规划一个个振奋人心的目标,让大家对工作充满了热情.然而好的开头却缺少追踪反馈没有好的结尾,那些大家所渴望达成的目标随着时间的流逝便逐渐没有了音信,不再有人主动提起,团队成员迎来的 ...

  8. python基础知识总结大全(转载)

  9. centos 较新版本kernel安装方法

    有时因为系统内核的bug 我们必须要安装新版本的kernel 来解决问题,有几种方法 源码编译 使用编译好的包 使用包的方式比较方便,同时一些依赖的问题可以自动帮助我们处理 添加yum 源 rpm - ...

  10. 机器学习---朴素贝叶斯与逻辑回归的区别(Machine Learning Naive Bayes Logistic Regression Difference)

    朴素贝叶斯与逻辑回归的区别: 朴素贝叶斯 逻辑回归 生成模型(Generative model) 判别模型(Discriminative model) 对特征x和目标y的联合分布P(x,y)建模,使用 ...