说明

该文章翻译自
http://www.javacodegeeks.com/2015/06/java-programming-tips-best-practices-beginners.html
只翻译了常用的,本人也是java初学者,中间也有自己的理解如有翻译不妥,欢迎纠正

返回空的集合而不是 null

当你设计的函数返回一个集合时,请确保当集合没有元素时返回一个空的集合,而不是null,这样可以节省 if-else 的判断

1
2
3
public class getLocationName {
return (null==cityName ? "": cityName);
}

要小心使用 String 类型

如果在循环中对字符串进行+ 运算,那么每次+ 运算就会创建新的 String 实例,这样就导致了大量的内存浪费。另外在实例化String 时,要尽量避免使用构造函数实例化,而是使用直接使用常量字符串赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
String str = new String();
for(int i=0;i<100;i++)
{
str = str + i;
}
// 循环完后就创建了101 的String 实例
// 可以使用StringBuffer 代替String
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < 10; i++) {
stringBuffer.append(i);
}

//Slower Instantiation[实例化较慢]
String bad = new String("Yet another string object");

//Faster Instantiation[实例化较快]
String good = "Yet another string object"

要尽量避免重复实例化对象

在使用的时候再创建对象,创建完后不要再重复创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;
}
}

Array 与 ArrayList 的区别和使用

Array 特点:

  • 固定的数组大小,不能方便的扩展大小,所以内存在使用时就已经分配好
  • 可以声明多维数组

ArrayList 特点

  • 大小不确定,可以随时添加元素
  • add/remove 元素很方便
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class arrayVsArraylist {

public static void main(String[] args) {
// TODO Auto-generated method stub
try {

int[] myArray = new int[6];
myArray[6] = 10;

ArrayList<Integer> myArrayList = new ArrayList<Integer>();

myArrayList.add(1);
myArrayList.add(2);
myArrayList.add(4);
myArrayList.add(3);

myArrayList.remove(1);

for (int aindex = 0; aindex < myArrayList.size(); aindex++) {
System.out.println(myArrayList.get(aindex));
}

int[][][] multiArray = new int[3][3][3];

} catch (Exception e) {
System.out.println("catch exception!!!" + e);
}
}
}

知道finally 语句块什么时候可以不会被执行

考虑如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class shutDownHooksDemo {
public static void main(String[] args) {
for(int i=0;i<5;i++)
{
try {
if(i==4) {
System.out.println("Inside Try Block.Exiting without executing Finally block.");
System.exit(0);
}
}
finally {
System.out.println("Inside Finally Block.");
}
}
}
}

初看上去 finally 语句块会被执行5次,但是当i==4 时 执行 System.exit(0) 后,finally 在这种情况下就不会被执行,因为当System.exit(0)执行后,就会所有正在运行的线程
,包括finnally语句块所在的线程,所以当第五次循环时,finallly 语句块永远都不会执行到。
当System.exit后,jvm会在程序结束前做两步清理工作

  • 执行使用 Runtime.addShutdownHook. 注册的 hutdown hooks 语句块,这对需要清理jvm之外的资源很有用处
  • 调用 Finalizers相关函数,System.runFinalizersOnExit 或者 Runtime.runFinalizersOnExit。但是该类函数已经不推荐使用,因为该方法可以操作正被其他线程占用的资源

检查奇偶性

使用第一种方法时,负数的情况就符合,第二种情况使用位运算速度既快[位运算是高度优化的],且不会出错。所以一些逻辑运算[加减乘除,除余]用位运算来代替。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 不正确的写法
public boolean oddOrNot(int num) {
return num % 2 == 1;
}

// 正确的写法
public boolean oddOrNot(int num) {
return (num & 0x1) != 0;
}

// 将整数扩大到 2的n倍
num <<= n
// 将整数缩小的 2的n倍
num >>= n (>>> 是无符号右移)

单引号和双引号的区别

  • ‘’ 的变量在底层是以整形存储的,如 ‘a’ 存的是整数 97 ‘A’ 是整数 65, 打印出的是整数
  • “” 是已字符串变量存储的,打印时当然是以字符串形式打印的
1
2
3
4
5
6
7
8
9
public class Haha {
public static void main(String args[]) {
System.out.print("H" + "a");
System.out.print('H' + 'a');
}
}

output:
HA169

通过简单的技巧来避免内存泄露

内存泄露会导致程序性能下降,由于java程序的内存管理是自动的,这些过程程序员是不可控制的。但是仍然可以使用一些前人实践过得经验来避免内存泄露

  • 在进行数据库操作时,当查询结束后,要及时释放数据库连接句柄
  • 尽可能的使用 finally 语句块
  • 要释放存储在静态容器中的静态实例对象

要避免产生死锁

对于怎么避免死锁没有什么技巧可言,通常死锁产生是由于一个同步对象正在等待获得一种资源,而该资源同时被另一个同步对象占有着。
以下程序就阐述了就会产生死锁,因为两个线程都在等待获得资源,而该资源又被另一个线程所占有着

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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();
}
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...");
}
}
}
}
}

output:
Addition Thread: 13
Subtraction Thread: 7
Holding First Lock...
Holding Second Lock...
Addition Thread: Waiting for AddLock...
Subtraction Thread: Waiting for SubLock...

将Sub 线程占有的资源换下位置就可以解决死锁问题啦

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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...");
}
}
}
}

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...");
}
}
}
}
}

output:
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...

字符串查找

使用String 提供的 一系列 indexOf 函数来定位一个字符穿的位置。
该函数返回一个 String Object 指定 Sub String 或者 字符的位置, 没有则返回 -1

1
2
3
4
5
6
7
8
9
10
11
12
13
public class StringSearch {

public static void main(String[] args) {
String myString = "I am a String!";

if(myString.indexOf("String") == -1) {
System.out.println("String not Found!");
}
else {
System.out.println("String found at: " + myString.indexOf("String"));
}
}
}

罗列出目录下的文件名

给定目录名,列出当前目录下的普通文件名[支持递归遍历]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import java.io.File;

public class Test {

/**
* @function:
* @data:2015-6-22下午10:46:49
* @author: walter
* @param args
*
*/

public static void main(String[] args) {
// TODO Auto-generated method stub
String file = "E:\\workspace\\python\\hello";
Tree(file);
}

// 递归遍历给定目录/文件
public static void Tree(String name) {
File dir = new File(name);
if (!dir.exists()) {
return;
}
if (dir.isFile()) {
System.out.println("name: " + dir.getAbsolutePath());
return;
}
for (File file : dir.listFiles())
if (file.isDirectory()) {
Tree(file.getAbsolutePath());
} else {
System.out.println("name: " + file.getAbsolutePath());
}
}
}

简单的文件IO操作

java提供 FileInputStream, FileOutputStream类来进行文件的输入和输出,使用完后一定要记得调用 close 来关闭文件句柄所占的资源
并且程序需要捕获异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileTest {

/**
* @function:
* @data:2015-6-22下午11:35:01
* @author: walter
* @param args
*
*/

public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream(
"E:\\workspace\\java\\TestJava\\src\\com\\walter\\test\\FileTest.java");
out = new FileOutputStream(
"E:\\workspace\\java\\TestJava\\src\\com\\walter\\test\\out.txt");

int c = 0;
while ((c = in.read()) != -1) {
out.write(c);
}
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
}

留言

Jun 23 2015