java作为最受欢迎程度榜榜首语言,自然是广大开发者使用最多的语言。正因为有如此广泛的使用性,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));

第二个版本的代码,在执行的时候会提高不少的性能。

这些错误每个都很经典,解决它们对你的能力绝对是极大的提升。当然这并不是全部,如果还想了解关于这方面的其他内容,不妨关注我们,接下来,我还会为你带来容易出现的其他问题。希望可以帮你在java之路上扫清障碍。

细数那些Java程序员最容易犯那些错的更多相关文章

  1. 惊呆了!Java程序员最常犯的错竟然是这10个

    和绝大多数的程序员一样,我也非常的宅.周末最奢侈的享受就是逛一逛技术型网站,比如说 programcreek,这个小网站上有一些非常有意思的主题.比如说:Java 程序员最常犯的错竟然是这 10 个, ...

  2. Java程序员最常犯的错误盘点之Top 10

    1. 数组转ArrayList 为了实现把一个数组转换成一个ArrayList,很多Java程序员会使用如下的代码: Arrays.asList确实会返回一个ArrayList对象,但是该类是Arra ...

  3. Java程序员岗位

    Java程序员岗位面试题有哪些?   1.面向对象的特征有哪些方面(1)抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择 ...

  4. JAVA程序员面试宝典

    程序员面试之葵花宝典 面向对象的特征有哪些方面    1. 抽象:抽象就是忽略一个主题中与当前目标2. 无关的那些方面,3. 以便更充分地注意与当前目标4. 有关的方面.抽象并不5. 打算了解全部问题 ...

  5. 聊聊阿里社招面试,谈谈“野生”Java程序员学习的道路

    引言 很尴尬的是,这个类型的文章其实之前笔者就写过,原文章里,笔者自称LZ(也就是楼主,有人说是老子的简写,笔者只想说,这位同学你站出来,保证不打死你,-_-),原文章名称叫做<回答阿里社招面试 ...

  6. Java程序员面试之葵花宝典

    程序员面试之葵花宝典 1.面向对象的特征有哪些方面   抽象:抽象就是忽略一个主题中与当前目标 无关的那些方面, 以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而 只是选择其中的一部 ...

  7. Java程序员面试题收集(6)

    <!————————————————————————————基础题122道,代码题19道————————————————————————————> JAVA相关基础知识1.面向对象的特征有 ...

  8. [转载]一个标准java程序员的进阶过程

    第一阶段:Java程序员 技术名称 内                 容 说明 Java语法基础 基本语法.数组.类.继承.多态.抽象类.接口.object对象.常用类(Math\Arrarys\S ...

  9. Java程序员

    从生存.制胜.发展三个方面入手,为大家展示出程序员求职与工作的一幅3D全景图像.本书中既有在公司中的生存技巧,又有高手达人的进阶策略,既有求职攻略的按图索骥,又有入职后生产环境的破解揭秘. 书中浓缩了 ...

随机推荐

  1. 8、Python简单数据类型(int、float、complex、bool、str)

    一.数据类型分类 1.按存值个数区分 单个值:数字,字符串 多个值(容器):列表,元组,字典,集合 2.按可变不可变区分 可变:列表[],字典{},集合{} 不可变:数字,字符串,元组().bool, ...

  2. gdb命令行

    1.当程序出现core dump时,使用下面的命令调试:       gdb 程序名 core.1234  或       gdb core.1234       gdb -c core.1234 程 ...

  3. learning java NIO 之 RandomFileChannel

    import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.i ...

  4. 使用if和switch制作简单的年龄生肖判断

    -年 查询 --> var oDiv =document.getElementById("cont"); var oYear = document.getElementByI ...

  5. P3746 【[六省联考2017]组合数问题】

    题目是要我们求出如下柿子: \[\sum_{i=0}^{n}C_{nk}^{ik+r}\] 考虑k和r非常小,我们能不能从这里切入呢? 如果你注意到,所有组合数上方的数\(\%k==r\),那么是不是 ...

  6. 转载:SVD

    ComputeSVD        在分布式矩阵有CoordinateMatirx, RowMatrix, IndexedRowMatrix三种.除了CoordinateMatrix之外,Indexe ...

  7. GoCN每日新闻(2019-09-30)

    GoCN每日新闻(2019-09-30) 1. 使用Sqlmock测试数据库 https://medium.com/ralali-engineering/testing-database-using- ...

  8. mysql 生成随机数rand()

    mysql> select rand(); +--------------------+ | rand() | +--------------------+ | 0.99134733527092 ...

  9. vue+elementui搭建后台管理界面(7 vuex和mockjs的使用)

    将权限管理应用到系统,首先做好登录, 点击登录按钮后,触发以下动作 vuex 中的 login 动作,设置 cookie vuex 中的 getuserinfo , 获取权限.用户名.头像等 由于目前 ...

  10. C# 反射、使用场景

    创建一个 Console 控制台应用程序, 1. 创建一个 Project 类 public class Project { public int ID { get; set; } public st ...