怎么又出错了?盘点java中最容易出现的错误。

现如今,java已经广泛应用各种软件开发领域。基于面向对象的设计,java屏蔽了诸如C,C++等语言的一些复杂性,提供了垃圾回收机制,平台无关的虚拟机技术,Java创造了一种前所未有的开发方式。所以,java对比其他程序语言更加受欢迎。因此,Java中的异常也是随时发生,下面我就列出了我认为的Java开发最容易出现的10个错误。

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大神。

原文地址:https://blog.51cto.com/13007966/2458399

时间: 2024-08-15 09:52:13

怎么又出错了?盘点java中最容易出现的错误。的相关文章

java中包容易出现的错误及权限问题

/* 3,权限在不同地方的体现: public protected default private 同一类中: ok ok ok ok 同一包中: ok ok ok 子类中: ok ok 不同包中: ok 在同一包中子类中是可以访问父类中默认权限(default)的方法,但是在不同包中不行! 在不同包中如果子类继承了父类,那么子类就可以访问父类中的protected方法! */ //import mytest.*; /* package mytest; public class DemoA{ p

java中三种常见内存溢出错误的处理方法

更多 10 相信有一定java开发经验的人或多或少都会遇到OutOfMemoryError的问题,这个问题曾困扰了我很长时间,随着解决各类问题经验的积累以及对问题根源的探索,终于有了一个比较深入的认识. 在解决java内存溢出问题之前,需要对jvm(java虚拟机)的内存管理有一定的认识.jvm管理的内存大致包括三种不同类型的内存区 域:Permanent Generation space(永久保存区域).Heap space(堆区域).Java Stacks(Java栈).其中永久保存区域主要

java中自己常犯的错误汇总

1package debug; 2 3/* 4 1.定义一个公共的动物类,包含名字.年龄.颜色和吃饭东西方法 5 2.定义一个猫类,继承动物类,同时拥有玩游戏的本领 6 3.定义一个狗类,继承动物类,同时拥有看门的本领 7/ 8 9class Animal{10private String name;11privateint age;12private String color;1314public Animal() {1516 }1718publicAnimal(String name,int

Java中的throw和throws的区别

Java中的throw和throws的区别 1.throw关键字用于方法体内部,而throws关键字用于方法体部的方法声明部分: 2.throw用来抛出一个Throwable类型的异常,而throws用来声明方法可能会抛出某些异常 Java中的throw和throws的区别,布布扣,bubuko.com

java中正则的使用

一:什么是正则表达式 1.定义:正则表达式是一种可以用于模式匹配和替换的规范,一个正则表达式就是由普通的字符(例如字符a到z)以及特殊字符(元字符)组成的文字模式,它 用以描述在查找文字主体时待匹配的一个或多个字符串.正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配. 2.用途: 字符串匹配(字符匹配) 字符串查找 字符串替换 字符串分割 例如: 从网页中揪出email地址 IP地址是否正确 从网页中揪出链接 3.java中处理正则表达式的类: java.lang.String j

Java面试题:Java中的集合及其继承关系

关于集合的体系是每个人都应该烂熟于心的,尤其是对我们经常使用的List,Map的原理更该如此.这里我们看这张图即可: 1.List.Set.Map是否继承自Collection接口? List.Set 是,Map 不是.Map是键值对映射容器,与List和Set有明显的区别,而Set存储的零散的元素且不允许有重复元素(数学中的集合也是如此),List是线性结构的容器,适用于按数值索引访问元素的情形. 2.阐述ArrayList.Vector.LinkedList的存储性能和特性. ArrayLi

在java中public void与public static void区别

static 方法可以被main方法直接调用,而非static方法不可以.因为static方法是属于类的,是类方法.可以通过类名.方法名直接调用.而非static方法必须等对象被new出来以后才能使用,因而不能在main中直接调用. public void 修饰是非静态方法,该类方法属于对象,在对象初始化(new Object())后才能被调用:public static void 修饰是静态方法,属于类,使用类名.方法名直接调用. Java 可以通过对象名调用静态方法(对象名.静态方法).Ja

完成这个例子,说出java中针对异常的处理机制。

有一个类为ClassA,有一个类为ClassB,在ClassB中有一个方法b,此方法抛出异常,在ClassA类中有一个方法a,请在这个方法中调用b,然后抛出异常.在客户端有一个类为TestC,有一个方法为c ,请在这个方法中捕捉异常的信息.完成这个例子,请说出java中针对异常的处理机制. [java] view plaincopy package com.itheima; import java.io.IOException; /** *第6题:有一个类为ClassA,有一个类为ClassB,

Java中抛出的各种异常

目录(?)[-] 引子 JAVA异常 处理异常机制 捕获异常trycatch 和 finally try-catch语句 trycatch-finally语句 try-catch-finally 规则异常处理语句的语法规则 trycatchfinally语句块的执行顺序 抛出异常 throws抛出异常 使用throw抛出异常 Throwable类中的常用方法 Java常见异常 runtimeException子类 IOException 其他 自定义异常 1. 引子 try…catch…fina