您的位置:首页 > 编程语言 > Java开发

java初学者常见的问题

2016-03-30 09:17 399 查看
本文为那些准Java程序员们准备了一系列广为流传的Java最佳编程实践:1.    优先返回空集合而非null如果程序要返回一个不包含任何值的集合,确保返回的是空集合而不是null。这能节省大量的”if else”检查。publicclass getLocationName {
    return(null==cityName ?"": cityName);
}1.    谨慎操作字符串如果两个字符串在for循环中使用+操作符进行拼接,那么每次循环都会产生一个新的字符串对象。这不仅浪费内存空间同时还会影响性能。类似的,如果初始化字符串对象,尽量不要使用构造方法,而应该直接初始化。比方说://Slower Instantiation
String bad =newString("Yet another string object");
     
//FasterInstantiation
String good ="Yet another string object"1.    避免无用对象创建对象是Java中最昂贵的操作之一。因此最好在有需要的时候再进行对象的创建/初始化。如下:import java.util.ArrayList;
import java.util.List;

publicclassEmployees{

    privateListEmployees;

    publicList getEmployees(){

        //initialize only when required
        if(null==Employees){
            Employees=newArrayList();
        }
        returnEmployees;
    }
}1.    数组与ArrayList之争开发人员经常会发现很难在数组和ArrayList间做选择。它们二者互有优劣。如何选择应该视情况而定。import java.util.ArrayList;

publicclass arrayVsArrayList {

    publicstaticvoid main(String[] args){
        int[] myArray =newint[6];
        myArray[7]=10;//ArraysOutOfBoundException

        //Declaration of ArrayList. Add and Remove of elements is easy.
        ArrayList<Integer> myArrayList =newArrayList<>();
        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 =newint[3][3][3];
    }
}·        数组是定长的,而ArrayList是变长的。由于数组长度是固定的,因此在声明数组时就已经分配好内存了。而数组的操作则会更快一些。另一方面,如果我们不知道数据的大小,那么过多的数据便会导致ArrayOutOfBoundException,而少了又会浪费存储空间。·        ArrayList在增删元素方面要比数组简单。·        数组可以是多维的,但ArrayList只能是一维的。1.    try块的finally块没有被执行看下下面这段代码:publicclass shutDownHooksDemo {
    publicstaticvoid main(String[] args){
        for(int i=0;i<5;i++)
        {
            try{
                if(i==4){
                    System.out.println("Inside Try Block.Exiting withoutexecuting Finally block.");
                    System.exit(0);
                }
            }
            finally{
                System.out.println("Inside Finally Block.");
            }
        }
    }
}从代码来看,貌似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可以在存活对象上进行调用,即便是这些对象仍在被其它线程所使用。而这会导致不可预期的结果甚至是死锁。publicclass shutDownHooksDemo {

    publicstaticvoid main(String[] args){
            for(int i=0;i<5;i++)
            {
                    finalint final_i = i;
                    try{
                           Runtime.getRuntime().addShutdownHook(
                                           newThread(){
                                           publicvoid run(){
                                           if(final_i==4){
                                           System.out.println("Inside Try Block.Exiting withoutexecuting Finally block.");
                                           System.exit(0);
                                           }
                                           }
                                           });
                    }
                    finally{
                           System.out.println("InsideFinally Block.");
                    }

            }
    }
}1.    判断奇数看下这几行代码,看看它们是否能用来准确地判断一个数是奇数?publicboolean oddOrNot(int num){
    return num %2==1;
}看似是对的,但是每执行四便会有一个错误的结果(用数据说话)。考虑到负奇数的情况,它除以2的结果就不会是1。因此,返回值是false,而这样是不对的。代码可以修改成这样:publicboolean oddOrNot(int num){
    return(num &1)!=0;
}这么写不光是负奇数的问题解决了,并且还是经过充分优化过的。因为算术运算和逻辑运行要比乘除运算更高效,计算的结果也会更快。1.    单引号与双引号的区别publicclassHaha{
    publicstaticvoid main(String args[]){
    System.out.print("H"+"a");
    System.out.print('H'+'a');
    }
}看起来这段代码会返回”Haha”,但实际返回的是Ha169。原因就是用了双引号的时候,字符会被当作字符串处理,而如果是单引号的话,字符值会通过一个叫做基础类型拓宽的操作来转换成整型值。然后再将值相加得到169。1.    一些防止内存泄露的小技巧内存泄露会导致软件的性能降级。由于Java是自动管理内存的,因此开发人员并没有太多办法介入。不过还是有一些方法能够用来防止内存泄露的。·        查询完数据后立即释放数据库连接·        尽可能使用finally块·        释放静态变量中的实例1.    避免死锁死锁出现的原因有很多。避免死锁不是一句话就能解决的。通常来说,当某个同步对象在等待另一个同步对象所拥有的资源上的锁时,便会产生死锁。试着运行下下面的程序。它会告诉你什么是死锁。这个死锁是由于两个线程都在等待对方所拥有的资源,因此会产生死锁。它们会一直等待,没有谁会先放手。publicclassDeadlockDemo{
   publicstaticObject addLock =newObject();
   publicstaticObject subLock =newObject();

   publicstaticvoid main(String args[]){

      MyAdditionThread add =newMyAdditionThread();
      MySubtractionThreadsub=newMySubtractionThread();
      add.start();
      sub.start();
   }
privatestaticclassMyAdditionThreadextendsThread{
      publicvoid 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 forAddLock...");
            synchronized(subLock){
               System.out.println("Threads: Holding Add and SubLocks...");
            }
         }
      }
   }
   privatestaticclassMySubtractionThreadextendsThread{
      publicvoid 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 forSubLock...");
            synchronized(addLock){
               System.out.println("Threads: Holding Add and SubLocks...");
            }
         }
      }
   }
}输出:AdditionThread:13
SubtractionThread:7
HoldingFirstLock...
HoldingSecondLock...
AdditionThread:WaitingforAddLock...
Subtraction  Thread:WaitingforSubLock...但如果调用的顺序变一下的话,死锁的问题就解决了。publicclassDeadlockSolutionDemo{
   publicstaticObject addLock =newObject();
   publicstaticObject subLock =newObject();

   publicstaticvoid main(String args[]){

      MyAdditionThread add =newMyAdditionThread();
      MySubtractionThreadsub=newMySubtractionThread();
      add.start();
      sub.start();
   }

privatestaticclassMyAdditionThreadextendsThread{
      publicvoid 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 forAddLock...");
            synchronized(subLock){
               System.out.println("Threads: Holding Add and SubLocks...");
            }
         }
      }
   }
   
   privatestaticclassMySubtractionThreadextendsThread{
      publicvoid 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 forSubLock...");
            synchronized(subLock){
               System.out.println("Threads: Holding Add and SubLocks...");
            }
         }
      }
   }
}输出:AdditionThread:13
HoldingFirstLock...
AdditionThread:WaitingforAddLock...
Threads:HoldingAddandSubLocks...
SubtractionThread:7
HoldingSecondLock...
Subtraction  Thread:WaitingforSubLock...
Threads:HoldingAddandSubLocks...1.    替Java省点内存某些Java程序是CPU密集型的,但它们会需要大量的内存。这类程序通常运行得很缓慢,因为它们对内存的需求很大。为了能提升这类应用的性能,可得给它们多留点内存。因此,假设我们有一台拥有10G内存的Tomcat服务器。在这台机器上,我们可以用如下的这条命令来分配内存:export JAVA_OPTS="$JAVA_OPTS -Xms5000m -Xmx6000m-XX:PermSize=1024m -XX:MaxPermSize=2048m"·        Xms = 最小内存分配·        Xmx = 最大内存分配·        XX:PermSize = JVM启动时的初始大小·        XX:MaxPermSize = JVM启动后可分配的最大空间1.    如何计算Java中操作的耗时在Java中进行操作计时有两个标准的方法:System.currentTimeMillis()和System.nanoTime()。问题就在于,什么情况下该用哪个。从本质上来讲,他们的作用都是一样的,但有以下几点不同:1.    System.currentTimeMillis()的精度在千分之一秒到千分之15秒之间(取决于系统)而System.nanoTime()则能到纳秒级。2.    System.currentTimeMillis读操作耗时在数个CPU时钟左右。而System.nanoTime()则需要上百个。3.    System.currentTimeMillis对应的是绝对时间(1970年1 月1日所经历的毫秒数),而System.nanoTime()则不与任何时间点相关。4.    Float还是double
数据类型所用字节有效位数
float47
double815
在对精度要求高的场景下,double类型相对float要更流行一些,理由如下:大多数处理器在处理float和double上所需的时间都是差不多的。而计算时间一样的前提下,double类型却能提供更高的精度。1.    幂运算Java是通过异或操作来进行幂运算的。Java对于幂运算有两种处理方式:·        乘积:double square =double a *double a;                          // Optimized
double cube =double a *double a *double a;                   // Non-optimized
double cube =double a *double square;                      // Optimized
double quad =double a *double a *double a *double a;          // Non-optimized
double quad =double square *double square;                 // Optimized·        pow方法:在无法使用乘积的情况下可以使用pow方法。double cube =Math.pow(base, exponent);不到万不得已不要使用Math.pow。比方说,当指数是小数的时候。因为Math.pow要比乘积慢300-600倍左右。1.    如何处理空指针异常空指针异常是Java中很常见的异常。当你尝试调用一个null对象上的方法时便会抛出这个异常。比如:int noOfStudents = school.listStudents().count;在上述例子中,school为空或者listStudents()为空都可能会抛出了NullPointerException。因此最好检查下对象是否为空以避免类似情况。privateint getListOfStudents(File[] files){
      if(files ==null)
        thrownewNullPointerException("File list cannot be null");
    }1.    JSON编码JSON是数据存储及传输的一种协议。与XML相比,它更易于使用。由于它非常轻量级以及自身的一些特性,现在JSON在网络上已经是越来越流行了。常见的数据结构都可以编码成JSON然后在各个网页间自由地传输。不过在开始编码前,你得先安装一个JSON解析器。在下面的例子中,我们将使用json.simple库来完成这项工作 (https://code.google.com/p/json-simple/)。下面是编码成JSON串的一个简单的例子。import org.json.simple.JSONObject;
import org.json.simple.JSONArray;

publicclassJsonEncodeDemo{
   
    publicstaticvoid main(String[] args){
       
        JSONObject obj =newJSONObject();
        obj.put("Novel Name","Godaan");
        obj.put("Author","Munshi Premchand");
 
        JSONArray novelDetails =newJSONArray();
        novelDetails.add("Language:Hindi");
        novelDetails.add("Year ofPublication: 1936");
        novelDetails.add("Publisher:Lokmanya Press");
       
        obj.put("Novel Details", novelDetails);
       
        System.out.print(obj);
    }
}输出:{"Novel Name":"Godaan","Novel Details":["Language: Hindi","Year of Publication: 1936","Publisher: Lokmanya Press"],"Author":"Munshi Premchand"}1.    JSON解析开发人员要想解析JSON串,首先你得知道它的格式。下面例子有助于你来理解这一点:import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

publicclassJsonParseTest{

    privatestaticfinalString filePath ="//home//user//Documents//jsonDemoFile.json";
   
    publicstaticvoid main(String[] args){

        try{
            // read the json file
            FileReader reader =newFileReader(filePath);
            JSONParser jsonParser =newJSONParser();
            JSONObject jsonObject =(JSONObject)jsonParser.parse(reader);
           
            // get a number from the JSON object
            Long id =  (Long) jsonObject.get("id");
            System.out.println("The id is: "+ id);         

            // get a String from the JSON object
            String   type =(String) jsonObject.get("type");
            System.out.println("The type is: "+ type);

            // get a String from the JSON object
            String   name =(String) jsonObject.get("name");
            System.out.println("The name is: "+ name);

            // get a number from the JSON object
            Double ppu =  (Double) jsonObject.get("ppu");
            System.out.println("The PPU is: "+ ppu);
           
            // get an array from the JSON object
            System.out.println("Batters:");
            JSONArray batterArray=(JSONArray) jsonObject.get("batters");
            Iterator i = batterArray.iterator();
            // take each value from the json arrayseparately
            while(i.hasNext()){
                JSONObject innerObj =(JSONObject) i.next();
                System.out.println("ID "+ innerObj.get("id")+
                       " type"+ innerObj.get("type"));
            }

            // get an array from the JSON object
            System.out.println("Topping:");
            JSONArray toppingArray=(JSONArray) jsonObject.get("topping");
            Iterator j = toppingArray.iterator();
            // take each value from the json arrayseparately
            while(j.hasNext()){
                JSONObject innerObj =(JSONObject) j.next();
                System.out.println("ID "+ innerObj.get("id")+
                       " type"+ innerObj.get("type"));
            }
           

        }catch(FileNotFoundException ex){
            ex.printStackTrace();
        }catch(IOExceptionex){
            ex.printStackTrace();
        }catch(ParseExceptionex){
            ex.printStackTrace();
        }catch(NullPointerException ex){
            ex.printStackTrace();
        }

    }

}jsonDemoFile.json{
    "id":0001,
    "type":"donut",
    "name":"Cake",
    "ppu":0.55,
    "batters":
        [
            {"id":1001,"type":"Regular"},
            {"id":1002,"type":"Chocolate"},
            {"id":1003,"type":"Blueberry"},
            {"id":1004,"type":"Devil's Food"}
        ],
    "topping":
        [
            {"id":5001,"type":"None"},
            {"id":5002,"type":"Glazed"},
            {"id":5005,"type":"Sugar"},
            {"id":5007,"type":"Powdered Sugar"},
            {"id":5006,"type":"Chocolate with Sprinkles"},
            {"id":5003,"type":"Chocolate"},
            {"id":5004,"type":"Maple"}
        ]
}The id is:1
The type is: donut
The name is:Cake
The PPU is:0.55
Batters:
ID 1001 type Regular
ID 1002 type Chocolate
ID 1003 type Blueberry
ID 1004 type Devil's Food
Topping:
ID 5001 type None
ID 5002 type Glazed
ID 5005 type Sugar
ID 5007 type Powdered Sugar
ID 5006 type Chocolate with Sprinkles
ID 5003 type Chocolate
ID 5004 type Maple1.    简单字符串查找Java提供了一个库函数叫做indexOf()。这个方法可以用在String对象上,它返回的是要查找的字符串所在的位置序号。如果查找不到则会返回-1。1.    列出目录下的文件你可以用下面的代码来列出目录下的文件。这个程序会遍历某个目录下的所有子目录及文件,并存储到一个数组里,然后通过遍历数组来列出所有文件。import java.io.*;

publicclassListContents{
    publicstaticvoid main(String[] args){
        File file =newFile("//home//user//Documents/");
        String[] files = file.list();

        System.out.println("Listingcontents of "+ file.getPath());
        for(int i=0; i < files.length ; i++)
        {
            System.out.println(files[i]);
        }
    }
}1.    一个简单的IO程序Java提供了FileInputStream以及FileOutputStream类来进行文件的读写操作。FileInputStream的构造方法会接收输入文件的路径作为入参然后创建出一个文件的输入流。同样的,FileOutputStream的构造方法也会接收一个文件路径作为入参然后创建出文件的输出流。在处理完文件之后,一个很重要的操作就是要记得”close”掉这些流。import java.io.*;

publicclass myIODemo {
    publicstaticvoid main(String args[])throwsIOException{
        FileInputStreamin=null;
        FileOutputStreamout=null;
       
        try{
            in=newFileInputStream("//home//user//Documents//InputFile.txt");
            out=newFileOutputStream("//home//user//Documents//OutputFile.txt");
           
            int c;
            while((c =in.read())!=-1){
                out.write(c);
            }
        }finally{
            if(in!=null){
                in.close();
            }
            if(out!=null){
                out.close();
            }
        }
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: