- 浏览: 49466 次
- 性别:
文章分类
最新评论
java初学者常见的问题
本文为那些准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
数据类型 | 所用字节 | 有效位数 |
float | 4 | 7 |
double | 8 | 15 |
在对精度要求高的场景下,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 Maple
1. 简单字符串查找
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();
}
}
}
}
相关推荐
### Java初学者必看:深入理解Java垃圾回收机制 对于Java初学者而言,理解Java的垃圾回收机制(Garbage Collection, GC)是非常重要的。在C++等其他编程语言中,程序员需要手动管理内存,比如使用new分配内存后,还...
下面我们将详细探讨Java初学者在220个实例中可能会遇到的知识点。 1. **基础语法**:包括变量声明、数据类型(如整型、浮点型、字符型、布尔型)、运算符(算术、比较、逻辑、位操作等)、流程控制(如if-else、...
通过这些练习题,初学者不仅可以巩固理论知识,还能提高实际编程能力,解决实际问题。建议按照题目的难易程度逐步进行,每完成一道题目都要深入理解其背后的原理,这样才能真正掌握Java编程,并为更高级的开发工作...
Java初学者代码集合 在编程世界中,Java是一种广泛应用的高级编程语言,以其跨平台、面向对象和安全性著称。本资源"java初学者代码"是专为那些刚刚接触Java编程的人准备的,旨在帮助他们快速理解Java的编程基础和...
在Java编程语言中,学习和理解基本词汇是初学者入门的关键。以下是一些核心概念的详细解释: 1. **Abstract Window Toolkit (AWT)**:AWT是Java早期提供的一种图形用户界面(GUI)工具包,它使用本地操作系统提供的...
### JAVA初学者应该明白的问题 对于Java初学者而言,在学习过程中往往会遇到许多令人困惑的问题。这些问题不仅涉及到语言的基础概念,还包括一些进阶的用法与理解。本文将针对一些常见的问题进行详细的解释与分析,...
【JAVA初学者_扫雷源码】是一个适合初级JAVA学习者参考的项目,它展示了如何用JAVA编程语言实现经典游戏“扫雷”。这个项目对于理解JAVA基础语法、控制流程、面向对象编程等概念非常有帮助。 1. **JAVA基础语法**:...
JAVA初学者常见的的30个不同于其他编程语言的问题.pdf
【Java初学者适用——Java实例大全】是一份专为初学者设计的教程资源,它涵盖了大量实际编程案例,旨在帮助新手快速掌握Java编程语言。在Java的世界里,实践是掌握知识的关键,通过实例学习能够更好地理解和应用理论...
"Java初学者实例源码"是一个集合,旨在帮助初学者逐步理解并实践Java的各种功能和编程技巧。这个压缩包文件包含了一系列的Java源代码示例,涵盖了基础到进阶的多个主题。 1. **基础语法**:Java的基础语法包括变量...
"220个Java初学者实例源码"是一个非常宝贵的资源,它包含了大量实际编程案例,可以帮助新手快速理解和掌握Java的核心概念。 首先,我们可以从这些实例中学习Java的基础语法。这包括变量声明、数据类型(如整型、...
【标题】"java 初学者 网址 大全" 涵盖了一系列适合Java初学者的在线学习资源,这些资源旨在帮助新手快速掌握Java编程语言的基础和进阶知识。"详细"一词表明了这些网址提供的内容深入且全面,涵盖了从基本语法到实际...
Java是世界上最流行的编程语言之一,尤其适合初学者作为学习编程的起点。本资源包提供了丰富的学习资料,旨在帮助初学者逐步掌握Java基础知识,熟练运用Java常用类,并最终达到精通Java编程的目标。 首先,"JAVA_...
Java 编程语言是当前最流行的编程语言之一,对于初学者来说,选择合适的书籍学习是非常重要的。在这里,我们推荐了多本 Java 编程书籍,涵盖了入门、进阶、J2EE 等多个方面。 入门 * 《Head First Java, 2nd ...
### Java初学者指南:从零开始到项目实战 #### 一、Java简介与特性 Java是一种广泛使用的高级编程语言,自1995年由Sun Microsystems公司发布以来,因其跨平台性和安全性等特点,迅速成为了企业级应用开发的重要...
### JAVA初学者必看的学习方法 对于初学者来说,在学习JAVA的过程中可能会遇到各种各样的问题,这不仅仅是因为JAVA本身的复杂性,还因为学习路径的选择、方法的掌握等多方面因素。下面将根据提供的部分信息,深入...
根据给定文件的信息,我们可以提炼出六个主要的知识点,这些知识点对于Java初学者来说非常重要。 ### 一、学好框架 在Java开发中,框架(framework)是非常重要的组成部分,它可以帮助开发者快速构建应用程序,...
以下是一些关于Java初学者常见的问题及其详细解释: 1. **String对象不可改变**:在Java中,String对象一旦创建,就不能修改。这是因为String对象存储在常量池中,其值是不可变的。例如,当执行`s = s.concat("ef")...
标题中的“Java初学者必备”意味着本文将关注Java的基础知识,包括JDK的配置,这对于在任何操作系统上开发Java应用程序都是必要的。描述中提到的“JDK的配置”是指Java Development Kit的安装和环境变量设置,这使得...