编程语言
首页 > 编程语言> > Java开发最容易踩的十个大坑,每条都是血的教训!

Java开发最容易踩的十个大坑,每条都是血的教训!

作者:互联网

本文为Java程序员们准备了一系列广为流传的Java最佳编程实践,请认真读几遍(尤其是小白)。

认真看完后,必有收获,日后开发可以少踩坑!

文末干货:Java业务开发常见错误100例

1.优先返回空对象而非null

如果程序要返回一个对象,确保返回的对象有值而不是null。这能节省大量的"if else"检查。

public String getLocationName {    return (null == cityName ? "": cityName);}

2.谨慎操作字符串

如果两个字符串在for循环中使用+操作符进行拼接,那么每次循环都会产生一个新的字符串对象。这不仅浪费内存空间同时还会影响性能。类似的,如果初始化字符串对象,尽量不要使用构造方法,而应该直接初始化。比方说:

//Slower InstantiationString java = new String("百度搜 程序源码论坛 获精品");     //Faster InstantiationString soGood = "获更多最新精品资源"

3.避免无用对象

创建对象是Java中最昂贵的操作之一。因此最好在有需要的时候再进行对象的创建/初始化。如下:

import java.util.ArrayList;import java.util.List;public class Employees {    private List Employees;    public List getEmployees() {        //initialize only when required        if(null == Employees) {            Employees = new ArrayList();        }        return Employees;    }}

4.数组与ArrayList之争

开发人员经常会发现很难在数组和ArrayList间做选择。它们二者互有优劣。如何选择应该视情况而定。

import java.util.ArrayList;public class arrayVsArrayList {    public static void main(String[] args) {        int[] myArray = new int[6];        myArray[7]= 10; // ArraysOutOfBoundException        //Declaration of ArrayList. Add and Remove of elements is easy.        ArrayList<Integer> myArrayList = new ArrayList<>();        myArrayList.add(1);        myArrayList.add(2);        myArrayList.add(3);        myArrayList.add(4);        myArrayList.add(5);        myArrayList.remove(0);                for(int i = 0; i < myArrayList.size(); i++) {        System.out.println("Element: " + myArrayList.get(i));        }                //Multi-dimensional Array         int[][][] multiArray = new int [3][3][3];     }}

5.try块的finally块没有被执行

看下下面这段代码:

public class shutDownHooksDemo {    public static void main(String[] args) {        for(int i=0;i<5;i++)        {            try {                if(i==4) {                    System.out.println("程序源码论坛 www.cx1314.cn");                    System.exit(0);                }            }            finally {                System.out.println("最流行最优质的IT资源社区!");            }        }    }}

从代码来看,貌似finally块中的println语句应该会被执行5次。但当程序运行后,你会发现finally块只执行了4次。第5次迭代的时候会触发exit函数的调用,于是这第5次的finally便永远也触发不到了。原因便是——System.exit会挂起所有线程的执行,包括当前线程。即便是try语句后的finally块,只要是执行了exit,便也无力回天了。

在调用System.exit时,JVM会在关闭前执行两个结束任务:

首先,它会执行完所有通过Runtime.addShutdownHook注册进来的终止的钩子程序。这一点很关键,因为它会释放JVM外部的资源。

接下来的便是Finalizer了。可能是System.runFinalizersOnExit也可能是Runtime.runFinalizersOnExit。finalizer的使用已经被废弃有很长一段时间了。finalizer可以在存活对象上进行调用,即便是这些对象仍在被其它线程所使用。而这会导致不可预期的结果甚至是死锁。

public class shutDownHooksDemo {    public static void main(String[] args) {            for(int i=0;i<5;i++)            {                    final int final_i = i;                    try {                         Runtime.getRuntime().addShutdownHook(                          new Thread() {                           public void run() {                            if(final_i==4) {                             System.out.println("Inside Try Block.Exiting without executing Finally block.");                             System.exit(0);                            }                           }                          });                    }                    finally {                            System.out.println("Inside Finally Block.");                    }            }    }}

6.奇数判断

看下这几行代码,看看它们是否能用来准确地判断一个数是奇数?

public boolean oddOrNot(int num) {    return num % 2 == 1;}

看似是对的,但是每执行四便会有一个错误的结果(用数据说话)。考虑到负奇数的情况,它除以2的结果就不会是1。因此,返回值是false,而这样是不对的。

代码可以修改成这样:

public boolean oddOrNot(int num) {    return (num & 1) != 0;}

这么写不光是负奇数的问题解决了,并且还是经过充分优化过的。因为算术运算和逻辑运行要比乘除运算更高效,计算的结果也会更快。

7.单引号与双引号的区别

public class Haha {    public static void main(String args[]) {    System.out.print("H" + "a");    System.out.print('H' + 'a');    }}

看起来这段代码会返回"Haha",但实际返回的是Ha169。原因就是用了双引号的时候,字符会被当作字符串处理,而如果是单引号的话,字符值会通过一个叫做基础类型拓宽的操作来转换成整型值。然后再将值相加得到169。

8.一些防止内存泄露的小技巧

内存泄露会导致软件的性能降级。由于Java是自动管理内存的,因此开发人员并没有太多办法介入。不过还是有一些方法能够用来防止内存泄露的。

9.避免死锁

死锁出现的原因有很多。避免死锁不是一句话就能解决的。通常来说,当某个同步对象在等待另一个同步对象所拥有的资源上的锁时,便会产生死锁。

试着运行下下面的程序。它会告诉你什么是死锁。这个死锁是由于两个线程都在等待对方所拥有的资源,因此会产生死锁。它们会一直等待,没有谁会先放手。

public class DeadlockDemo {   public static Object addLock = new Object();   public static Object subLock = new Object();   public static void main(String args[]) {      MyAdditionThread add = new MyAdditionThread();      MySubtractionThread sub = new MySubtractionThread();      add.start();      sub.start(); // 更多最新精品资源 www.cx1314.cn     }private static class MyAdditionThread extends Thread {      public void run() {         synchronized (addLock) {        int a = 10, b = 3;         int c = a + b;               System.out.println("Addition Thread: " + c);            System.out.println("Holding First Lock...");            try { Thread.sleep(10); }            catch (InterruptedException e) {}            System.out.println("Addition Thread: Waiting for AddLock...");            synchronized (subLock) {               System.out.println("Threads: Holding Add and Sub Locks...");            }         }      }   }   private static class MySubtractionThread extends Thread {      public void run() {         synchronized (subLock) {        int a = 10, b = 3;        int c = a - b;            System.out.println("Subtraction Thread: " + c);            System.out.println("Holding Second Lock...");            try { Thread.sleep(10); }            catch (InterruptedException e) {}            System.out.println("Subtraction  Thread: Waiting for SubLock...");            synchronized (addLock) {               System.out.println("Threads: Holding Add and Sub Locks...");            }         }      }   }}

输出:

Addition Thread: 13

Subtraction Thread: 7

Holding First Lock...

Holding Second Lock...

Addition Thread: Waiting for AddLock...

Subtraction Thread: Waiting for SubLock...

但如果调用的顺序变一下的话,死锁的问题就解决了。

public class DeadlockSolutionDemo {   public static Object addLock = new Object();   public static Object subLock = new Object();   public static void main(String args[]) {      MyAdditionThread add = new MyAdditionThread();      MySubtractionThread sub = new MySubtractionThread();      add.start();      sub.start();   }private static class MyAdditionThread extends Thread {      public void run() {         synchronized (addLock) {        int a = 10, b = 3;        int c = a + b;            System.out.println("Addition Thread: " + c);            System.out.println("Holding First Lock...");            try { Thread.sleep(10); }            catch (InterruptedException e) {}            System.out.println("Addition Thread: Waiting for AddLock...");            synchronized (subLock) {               System.out.println("Threads: Holding Add and Sub Locks...");            }         }  // 更多最新精品资源 www.cx1314.cn         }   }      private static class MySubtractionThread extends Thread {      public void run() {         synchronized (addLock) {        int a = 10, b = 3;        int c = a - b;            System.out.println("Subtraction Thread: " + c);            System.out.println("Holding Second Lock...");            try { Thread.sleep(10); }            catch (InterruptedException e) {}            System.out.println("Subtraction  Thread: Waiting for SubLock...");            synchronized (subLock) {               System.out.println("Threads: Holding Add and Sub Locks...");            }         }      }   }}

输出:

Addition Thread: 13

Holding First Lock...

Addition Thread: Waiting for AddLock...

Threads: Holding Add and Sub Locks...

Subtraction Thread: 7

Holding Second Lock...

Subtraction Thread: Waiting for SubLock...

Threads: Holding Add and Sub Locks...

10.替Java省点内存

某些Java程序是CPU密集型的,但它们会需要大量的内存。这类程序通常运行得很缓慢,因为它们对内存的需求很大。为了能提升这类应用的性能,可得给它们多留点内存。因此,假设我们有一台拥有10G内存的Tomcat服务器。在这台机器上,我们可以用如下的这条命令来分配内存:

export JAVA_OPTS="$JAVA_OPTS -Xms5000m -Xmx6000m -XX:PermSize=1024m -XX:MaxPermSize=2048m"

 

分享学习资料:Java业务开发常见错误合集

下载学习:http://www.cx1314.cn/thread-3182-1-1.html

让你Get如下技能:

 

标签:...,Java,大坑,Thread,System,每条,println,public,out
来源: https://www.cnblogs.com/cxmanito/p/14149145.html