30个java编程小技巧

来源:互联网 发布:类似英文的拼音域名 编辑:程序博客网 时间:2024/06/03 16:35

1.return 一个空的集合,而不是 null

如果一个程序返回一个没有任何值的集合,请确保一个空集合返回,而不是空元素。这样你就不用去写一大堆 ”if else” 判断null元素。

30 个java编程技巧(最佳实践的初学者)一

Java 的标准库设计者已经在 Collections 类中放了一个空的 List 常量 EMPTY_LIST,除此之外,还有 EMPTY_MAP, EMPTY_SET,真是贴心。

2. 小心使用 String

因为字符串相加或者拼接的方式都会在对象池中查找字符串是否存在,如果不存在则创建,这样在拼接的过程中会产生大量中间过程的字符串,占用内存资源。StringBuilder效率优于StringBuffer,但是StringBuffer线程安全。

30 个java编程技巧(最佳实践的初学者)一
30 个java编程技巧(最佳实践的初学者)一
另外,在实例化一个字符串对象,构造函数应该避免发生直接实例化,例如:
30 个java编程技巧(最佳实践的初学者)一

3. 避免不必要的对象

一个最昂贵的操作(在内存利用率)是java对象的创建。因此,建议只在必要时创建或初始化对象。下面的代码给出了一个例子:

30 个java编程技巧(最佳实践的初学者)一
4.Array 和ArrayList 选择

ArrayList和Array是我们在实际编程中经常使用的容器,而且因为ArrayList相当于动态化的数组,所以它们之间有太多的相似,以至于我们在选择哪种来存储元素的时候,会有小小的迷惑,他们都有注解的优缺点,选择真的取决于你的真实场景。

30 个java编程技巧(最佳实践的初学者)一

4.1.Array 有固定大小但 ArrayList 的大小不同。由于Array 的大小是固定的,在Array 类型变量声明的时候,内存被分配。因此,Array 是非常快的。另一方面, 使用ArrayList的最大缺点就是当我们添加新的元素的时候,它是先检查内部数组的容量是否足够,如果不够,它会创建一个容量为原来数组两倍的新数组,���后将所有元素复制到新数组里,接着抛掉旧数组。这点真的很麻烦,因为每次都要这么搞,尤其是元素足够多的时候,这就真的是既影响内存又影响效率的问题,但通过单独测试它们的运行时间,发现其实差不多,最大的影响就是如果是有其他代码也需要使用到内存,那么Array依然不变,但是ArrayList就会变得慢多,相同情况下所花的时间是Array的四倍多(实际情况是远远不止)。

4.2.这是添加或删除元素从ArrayList 比Array更容易。

4.3.数组可以多维但ArrayList只有一个维度。

4.4.ArrayList因为内部是一个数组,所以它是可以转化为数组的。

4.5 两者的适用场合:

List list = new ArrayList();

虽然我们想要的确实是ArrayList而不是list,但是我们知道,父类是可以获得子类的引用并且使用子类的方法,所以这样我们就能同时使用List和ArrayList的方法而不用害怕出错了。

首先,一个重要的约束就是,List的声明区域一般是在main方法里(当然静态list也可以,但是我们一般使用的时候都只是当做存储元素的临时容器),而Array是可以在外部进行声明的,这时它就是全局数组。所以,单看这点,它们的使用已经有区别,如果想要保存一些在整个程序运行期间都会存在而且不变的数据,我们可以将它们放进一个全局数组里,但是如果我们单纯只是想要以数组的形式保存数据,方便我们进行查找,那么,我们就选择ArrayList。而且还有一个地方是必须知道的,就是如果我们需要对元素进行频繁的移动或删除,或者是处理的是超大量的数据,那么,使用ArrayList就真的不是一个好的选择,因为它的效率很低,使用数组进行这样的动作就很麻烦,那么,我们可以考虑选择LinkedList。

30 个java编程技巧(最佳实践的初学者)一

5.用try catch的时候,要加finally吗?

考虑下面的代码片断

30 个java编程���巧(最佳实践的初学者)一
运行结果:

在Finally代码块中

在Finally代码块中

在Finally代码块中

在Finally代码块中

在Try内部代码块,退出不执行Finally代码块

在运行代码前,它看起来像要打印 ”在Finally代码块中“ 5次。但是执行的结果只有4次。第五次打印的结果是 ”在Try内部代码块,退出不执行Finally代码块“。

关于 Java 虚拟机是如何编译 finally 语句块的问题,有兴趣的读者可以参考《 The JavaTM Virtual Machine Specification, Second Edition 》中 7.13 节 Compiling finally。那里详细介绍了 Java 虚拟机是如何编译 finally 语句块。实际上,Java 虚拟机会把 finally 语句块作为 subroutine(对于这个 subroutine 不知该如何翻译为好,干脆就不翻译了,免得产生歧义和误解。)直接插入到 try 语句块或者 catch 语句块的控制转移语句之前。但是,还有另外一个不可忽视的因素,那就是在执行 subroutine(也就是 finally 语句块)之前,try 或者 catch 语句块会保留其返回值到本地变量表(Local Variable Table)中。待 subroutine 执行完毕之后,再恢复保留的返回值到操作数栈中,然后通过 return 或者 throw 语句将其返回给该方法的调用者(invoker)。

将上面代码修改如下:

30 个java编程技巧(最佳实践的初学者)一
运行结果:

在Try内部代码块,退出不执行Finally代码块

在Try内部代码块,退出不执行Finally代码块

在Try内部代码块,退出不执行Finally代码块

在Try内部代码块,退出不执行Finally代码块

在Try内部代码块,退出不执行Finally代码块

总结:

这里就不过多的去具体分析整个过程有兴趣的朋友可找资料了解整个过程,一个小小的、看似简单的 finally 语句块背后居然隐藏了这么多玄机。看来,我们平时还是应该认真的阅读 Java 相关的基础文档,比如:Java 语言规范、Java 虚拟机规范等,很多棘手的问题都可以从中得到答案。只有真正的吃透了基础知识,才能达到运用自如的境界!

1> try、catch、finally语句中,在如果try语句有return语句,则返回的之后当前try中变量此时对应的值,此后对变量做任何的修改,都不影响try中return的返回值

2> 如果finally块中有return 语句,则返回try或catch中的返回语句忽略。

3 >如果finally块中抛出异常,则整个try、catch、finally块中抛出异常

所以使用try、catch、finally语句块中需要注意的是

1> 尽量在try或者catch中使用return语句。通过finally块中达到对try或者catch返回值修改是不可行的。

2 >finally块中避免使用return语句,因为finally块中如果使用return语句,会显示的消化掉try、catch块中的异常信息,屏蔽了错误的发生

3 >finally块中避免再次抛出异常,否则整个包含try语句块的方法回抛出异常,并且会消化掉try、catch块中的异常

6.奇数判断

看看下面的代码行,并确定如果他们可以用来精确地识别一个给定的数字是否是奇数?

30 个java编程技巧(最佳实践的初学者)一

奇数可以被定义为被2整除余数为1的整数。表达式 num% 2 计算的是 num整除 2 时所产生的余数,因此看起来这个程序应该能够正确运转。遗憾的是,它不能;它在四分之一的时间里返回的都是错误的答案。

为什么是四分之一?因为在所有的 int 数值中,有一半都是负数,而 isOdd 方法对于对所有负奇数的判断都会失败。在任何负整数上调用该方法都回返回 false ,不管该整数是偶数还是奇数。

这是 Java 对取余操作符(%)的定义所产生的后果。该操作符被定义为对于所有的 int 数值 a 和所有的非零 int 数值b,都满足下面的恒等式:

(a / b) * b + (a % b) == a

现在进行修改如下:

30 个java编程技巧(最佳实践的初学者)一

使用此代码,不仅是解决了奇数的负的问题,而且这个代码也高度优化。因为,算术和逻辑运算的速度更快,比除法和乘法,结果取得了更快。

7. 单引号和双引号之间的区别

30 个java编程技巧(最佳实践的初学者)一

尝试运行上面的程序。这个程序演示了一个死锁。这种死锁的产生是因为两个线程都在等待其他线程所抓取的资源。他们都不在任何一个版本。从代码,似乎还“HaHa”是回来了,但它实际上返回ha169。原因是,如果使用双引号,字符串对待,但在单引号的情况下,字符自动转换为int型,进行计算。

8. 通过简单的技巧避免内存泄漏

内存泄漏经常会导致软件的性能退化。因为,java自动管理内存,开发商没有太多的控制。但仍有一些标准的做法,可以用来防止内存泄漏。

当查询完成时,总是释放数据库连接。

尽量使用 Finally 块。

释放存储在静态表中的实例。

9. 避免死锁

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

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

30 个java编程技巧(最佳实践的初学者)一
30 个java编程技巧(最佳实践的初学者)一
30 个java编程技巧(最佳实践的初学者)一

运行结果:

Addition Thread: 13

Subtraction Thread: 7

Holding First Lock…

Holding Second Lock…

Addition Thread: Waiting for AddLock…

Subtraction Thread: Waiting for SubLock…

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

将 MySubtractionThread中的线程加锁顺序调换再看看

30 个java编程技巧(最佳实践的初学者)一

运行结果:

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…

三种用于避免死锁的技术:

1>加锁顺序

2>加锁时限

3>死锁检测

一个更好的方案是给这些线程设置优先级,让一个(或几个)线程回退,剩下的线程就像没发生死锁一样继续保持着它们需要的锁。如果赋予这些线程的优先级是固定不变的,同一批线程总是会拥有更高的优先级。为避免这个问题,可以在死锁发生的时候设置随机的优先级。

10.JAVA运行内存的设置

一些java应用程序可以被高度的CPU密集型以及他们需要很多内存。这样的应用程序通常运行速度慢,因为内存高的要求。所以,我们可以在相关的配置文件中进行修改调整内存大小。

Xms = 设置内存初始化的大小

Xmx = 设置最大能够使用内存的大小

XX:PermSize =初始大小,将分配给JVM的启动过程

XX:MaxPermSize = 最大尺寸可以分配JVM的启动过程

11. 如何在java时间操作

有java时间两种标准方法:

System.currentTimeMillis()、System.nanoTime()

平时产生随机数时我们经常拿时间做种子,比如用System.currentTimeMillis的结果,但是在执行一些循环中使用了System.currentTimeMillis,那么每次的结果将会差别很小,甚至一样,因为现代的计算机运行速度很快。后来看到java中产生随机数函数以及线程池中的一些函数使用的都是System.nanoTime。

>System.currentTimeMillis返回的是从1970.1.1 UTC 零点开始到现在的时间,精确到毫秒,平时我们可以根据System.currentTimeMillis来计算当前日期,星期几等,可以方便的与Date进行转换,

> System.nanoTime提供相对精确的计时,但是不能用他来计算当前日期,

所以在使用中,我们可以根据我们具体的目的去正确的选择他们。

12. Float 和Double的选择

Data typeBytes usedSignificant figures (decimal)Float47Double815

double应该比float更好用,原因:

大多数处理器需要几乎相同数量的处理时间来执行浮点和双运算的操作。在相同数量的计算时间双提供了更高的精度。

13. Java的乘方运算

java提供了两个方法:

Multiplication:乘法

30 个java编程技巧(最佳实践的初学者)一

pow(double base, double exponent):(base的exponent次方)

30 个java编程技巧(最佳实践的初学者)一
math.pow只应在必要时使用,像指数是一个分数。Math.pow()方法通常慢300-600倍的速度比乘法。

14. 如何处理空指针异常

空指针异常在java中是很常见的。当我们尝试调用一个空对象引用的方法时,这个异常会发生。例如:

30 个java编程技巧(最佳实践的初学者)一
如果在上面的例子中,如果得到一个NullPointerException异常,然后学校 是null 或liststudents()null。有个好注意你可以提早将异常抛出,通过提早抛出异常(又���"迅速失败"),异常得以清晰又准确堆栈信息立即反映出什么出了错(提供了非法参数值),为什么出错(文件名不能为空值),以及哪里出的错,菜鸟和高手都可能犯的一个错是,在程序有能力处理异常之前就捕获它。Java编译器通过要求检查出的异常必须被捕获或抛出而间接助长了这种行为。自然而然的做法就是立即将代码用try块包装起来,并使用catch捕获异常,以免编译器报错。
30 个java编程技巧(最佳实践的初学者)一


JSON编码

JSON是数据存储及传输的一种协议。与XML相比,它更易于使用。由于它非常轻量级以及自身的一些特性,现在JSON在网络上已经是越来越流行了。常见的数据结构都可以编码成JSON然后在各个网页间自由地传输。不过在开始编码前,你得先安装一个JSON解析器。在下面的例子中,我们将使用json.simple库来完成这项工作 (https://code.google.com/p/json-simple/)。

下面是编码成JSON串的一个简单的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.json.simple.JSONObject;
import org.json.simple.JSONArray;
public class JsonEncodeDemo {
    public static void main(String[] args) {
        JSONObject obj = new JSONObject();
        obj.put("Novel Name""Godaan");
        obj.put("Author""Munshi Premchand");
        JSONArray novelDetails = new JSONArray();
        novelDetails.add("Language: Hindi");
        novelDetails.add("Year of Publication: 1936");
        novelDetails.add("Publisher: Lokmanya Press");
        obj.put("Novel Details", novelDetails);
        System.out.print(obj);
    }
}

输出:

1
{"Novel Name":"Godaan","Novel Details":["Language: Hindi","Year of Publication: 1936","Publisher: Lokmanya Press"],"Author":"Munshi Premchand"}

JSON解析

开发人员要想解析JSON串,首先你得知道它的格式。下面例子有助于你来理解这一点:

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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;
public class JsonParseTest {
    private static final String filePath = "//home//user//Documents//jsonDemoFile.json";
    public static void main(String[] args) {
        try {
            // read the json file
            FileReader reader = new FileReader(filePath);
            JSONParser jsonParser = new JSONParser();
            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 array separately
            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 array separately
            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 (IOException ex) {
            ex.printStackTrace();
        catch (ParseException ex) {
            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

简单字符串查找

Java提供了一个库函数叫做indexOf()。这个方法可以用在String对象上,它返回的是要查找的字符串所在的位置序号。如果查找不到则会返回-1。

列出目录下的文件

你可以用下面的代码来列出目录下的文件。这个程序会遍历某个目录下的所有子目录及文件,并存储到一个数组里,然后通过遍历数组来列出所有文件。

1
2
3
4
5
6
7
8
9
10
11
12
import java.io.*;
public class ListContents {
    public static void main(String[] args) {
        File file = new File("//home//user//Documents/");
        String[] files = file.list();
        System.out.println("Listing contents of " + file.getPath());
        for(int i=0 ; i < files.length ; i++)
        {
            System.out.println(files[i]);
        }
    }
}

一个简单的IO程序

Java提供了FileInputStream以及FileOutputStream类来进行文件的读写操作。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
import java.io.*;
public class myIODemo {
    public static void main(String args[]) throws IOException {
        FileInputStream in = null;
        FileOutputStream out = null;
        try {
            in = new FileInputStream("//home//user//Documents//InputFile.txt");
            out = new FileOutputStream("//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中执行某个shell命令

Java提供了Runtime类来执行shell命令。由于这些是外部的命令,因此异常处理就显得异常重要。在下面的例子中,我们将通过一个简单的例子来演示一下。我们会在shell命令行中打开一个pdf文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class ShellCommandExec {
    public static void main(String[] args) {
        String gnomeOpenCommand = "gnome-open //home//user//Documents//MyDoc.pdf";
        try {
            Runtime rt = Runtime.getRuntime();
            Process processObj = rt.exec(gnomeOpenCommand);
            InputStream stdin = processObj.getErrorStream();
            InputStreamReader isr = new InputStreamReader(stdin);
            BufferedReader br = new BufferedReader(isr);
            String myoutput = "";
            while ((myoutput=br.readLine()) != null) {
                myoutput = myoutput+"/n";
            }
            System.out.println(myoutput);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}

使用正则

正则表达式的结构摘录如下(来源: Oracle官网)

字符

字符分类

预定义字符

边界匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches
{
    private static String pattern =  "^[_A-Za-z0-9-]+(//.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(//.[A-Za-z0-9]+)*(//.[A-Za-z]{2,})$";
    private static Pattern mypattern = Pattern.compile(pattern);
    public static void main( String args[] ){
        String valEmail1 = "testemail@domain.com";
        String invalEmail1 = "....@domain.com";
        String invalEmail2 = ".$$%%@domain.com";
        String valEmail2 = "test.email@domain.com";
        System.out.println("Is Email ID1 valid? "+validateEMailID(valEmail1));
        System.out.println("Is Email ID1 valid? "+validateEMailID(invalEmail1));
        System.out.println("Is Email ID1 valid? "+validateEMailID(invalEmail2));
        System.out.println("Is Email ID1 valid? "+validateEMailID(valEmail2));
    }
    public static boolean validateEMailID(String emailID) {
        Matcher mtch = mypattern.matcher(emailID);
        if(mtch.matches()){
            return true;
        }
        return false;
    }    
}

Java Swing的简单示例

有了Java的swing,你便可以编写GUI应用了。Java所提供的javax包中就包含了swing。使用swing来编写GUI程序首先需要继承下JFrame。然后在里面添加Box,然后便可以往里面添加诸如按钮,多选按钮,文本框等控件了。这些Box是放在Container的最外层的。

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
import java.awt.*; 
import javax.swing.*;  
public class SwingsDemo extends JFrame 
    public SwingsDemo() 
    {
        String path = "//home//user//Documents//images";
        Container contentPane = getContentPane(); 
        contentPane.setLayout(new FlowLayout());   
        Box myHorizontalBox = Box. createHorizontalBox();  
        Box myVerticleBox = Box. createVerticalBox();   
        myHorizontalBox.add(new JButton("My Button 1")); 
        myHorizontalBox.add(new JButton("My Button 2")); 
        myHorizontalBox.add(new JButton("My Button 3"));   
        myVerticleBox.add(new JButton(new ImageIcon(path + "//Image1.jpg"))); 
        myVerticleBox.add(new JButton(new ImageIcon(path + "//Image2.jpg"))); 
        myVerticleBox.add(new JButton(new ImageIcon(path + "//Image3.jpg")));   
        contentPane.add(myHorizontalBox); 
        contentPane.add(myVerticleBox);   
        pack(); 
        setVisible(true);
    
    public static void main(String args[]) { 
        new SwingsDemo(); 
    }  
}

使用Java播放音频

在Java中,播放音频是一个很常见的需求,尤其是在游戏开发里面。

下面这个DEMO演示了如何在Java中播放音频。

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
import java.io.*;
import java.net.URL;
import javax.sound.sampled.*;
import javax.swing.*;
// To play sound using Clip, the process need to be alive.
// Hence, we use a Swing application.
public class playSoundDemo extends JFrame {
   // Constructor
   public playSoundDemo() {
      this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      this.setTitle("Play Sound Demo");
      this.setSize(300200);
      this.setVisible(true);
      try {
         URL url = this.getClass().getResource("MyAudio.wav");
         AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
         Clip clip = AudioSystem.getClip();
         clip.open(audioIn);
         clip.start();
      catch (UnsupportedAudioFileException e) {
         e.printStackTrace();
      catch (IOException e) {
         e.printStackTrace();
      catch (LineUnavailableException e) {
         e.printStackTrace();
      }
   }
   public static void main(String[] args) {
      new playSoundDemo();
   }
}

导出PDF文件

将表格导出成pdf也是一个比较常见的需求。通过itextpdf,导出pdf也不是什么难事。

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
import java.io.FileOutputStream;
import com.itextpdf.text.Document;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
public class DrawPdf {
      public static void main(String[] args) throws Exception {
        Document document = new Document();
        PdfWriter.getInstance(document, new FileOutputStream("Employee.pdf"));
        document.open();
        Paragraph para = new Paragraph("Employee Table");
        para.setSpacingAfter(20);
        document.add(para);
        PdfPTable table = new PdfPTable(3);
        PdfPCell cell = new PdfPCell(new Paragraph("First Name"));
        table.addCell(cell);
        table.addCell("Last Name");
        table.addCell("Gender");
        table.addCell("Ram");
        table.addCell("Kumar");
        table.addCell("Male");
        table.addCell("Lakshmi");
        table.addCell("Devi");
        table.addCell("Female");
        document.add(table);
        document.close();
      }
    }

邮件发送

在Java中发送邮件也很简单。你只需装一下Java Mail这个jar包,放到你的类路径里即可。在下面的代码中,我们设置了几个基础属性,然后便可以发送邮件了:

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
import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
public class SendEmail
{
    public static void main(String [] args)
    {    
        String to = "recipient@gmail.com";
        String from = "sender@gmail.com";
        String host = "localhost";
        Properties properties = System.getProperties();
        properties.setProperty("mail.smtp.host", host);
        Session session = Session.getDefaultInstance(properties);
        try{
            MimeMessage message = new MimeMessage(session);
            message.setFrom(new InternetAddress(from));
            message.addRecipient(Message.RecipientType.TO,new InternetAddress(to));
            message.setSubject("My Email Subject");
            message.setText("My Message Body");
            Transport.send(message);
            System.out.println("Sent successfully!");
        }
        catch (MessagingException ex) {
            ex.printStackTrace();
        }
    }
}

计算时间

许多程序都需要精确的时间计量。Java提供了一个System的静态方法来支持这一功能:

1
2
3
4
5
6
currentTimeMillis():返回当前时间自新纪元时间以来的毫秒值,long类型。
long startTime = System.currentTimeMillis();
long estimatedTime = System.currentTimeMillis() - startTime;
nanoTime():返回系统计时器当前的精确时间,纳秒值,这也是long类型。nanoTime()主要是用于计算相对时间而非绝对时间。
long startTime = System.nanoTime();
long estimatedTime = System.nanoTime() - startTime;

图片缩放

图片缩放可以通过AffineTransform来完成。首先要生成一个输入图片的图片缓冲,然后通过它来渲染出缩放后的图片。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public class RescaleImage {
  public static void main(String[] args) throws Exception {
    BufferedImage imgSource = ImageIO.read(new File("images//Image3.jpg"));
    BufferedImage imgDestination = new BufferedImage(100100, BufferedImage.TYPE_INT_RGB);
    Graphics2D g = imgDestination.createGraphics();
    AffineTransform affinetransformation = AffineTransform.getScaleInstance(22);
    g.drawRenderedImage(imgSource, affinetransformation);
    ImageIO.write(imgDestination, "JPG"new File("outImage.jpg"));
  }
}

捕获鼠标动作

实现了MouseMotionListner接口后,便可以捕获鼠标事件了。 当鼠标进入到某个特定区域时便会触发MouseMoved事件,你便能捕获到这个移动的动作了。通过一个例子来看下:

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
import java.awt.event.*;
import javax.swing.*;
public class MouseCaptureDemo extends JFrame implements MouseMotionListener
{
    public JLabel mouseHoverStatus;
    public static void main(String args[]) 
    {
        new MouseCaptureDemo();
    }
    MouseCaptureDemo() 
    {
        setSize(500500);
        setTitle("Frame displaying Coordinates of Mouse Motion");
        mouseHoverStatus = new JLabel("No Mouse Hover Detected.", JLabel.CENTER);
        add(mouseHoverStatus);
        addMouseMotionListener(this);
        setVisible(true);
    }
    public void mouseMoved(MouseEvent e) 
    {
        mouseHoverStatus.setText("Mouse Cursor Coordinates => X:"+e.getX()+" | Y:"+e.getY());
    }
    public void mouseDragged(MouseEvent e) 
    {}
}
FileOutputStream Vs. FileWriter

在Java中有两种写文件的方式:FileOutputStream与FileWriter。开发人员经常会在它们之间犹豫不决。下面这个例子能帮忙你更好地理解在不同的场景下应该选择何种方案。首先我们来看一下实现:

使用FileOutputStream:

1
2
3
4
File foutput = new File(file_location_string);
FileOutputStream fos = new FileOutputStream(foutput);
BufferedWriter output = new BufferedWriter(new OutputStreamWriter(fos));
output.write("Buffered Content");

使用FileWriter:

1
2
3
FileWriter fstream = new FileWriter(file_location_string);
BufferedWriter output = new BufferedWriter(fstream);
output.write("Buffered Content");

根据Java的接口规范:

FileOutputStream是用于写入原始字节流比如图片流数据。如果是要写入字符流,则应该考虑使用FileWriter。

这样就很清楚了,写图片应该使用FileOutputStream而写文本则应该选择FileWriter。

附加建议

集合的使用

Java提供了许多集合类——比如,Vector,Stack,Hashtable等。所以鼓励开发人员尽可能地使用这些集合类有如下原因:

· 使用集合使得代码的可重用度更高。

· 集合类使得代码的结构更良好,更易于理解与维护。

· 最重要的是这些集合类都经过充分的测试,代码质量很高。

1-50-500规则

在大型软件系统中,代码的可维护性是件很有挑战的工作。新加入的开发人员经常会抱怨这些情况:单片代码(Monolithic Code),意大利面式代码(spaghetti code, 常用于描述捆绑在一起并且低内聚的类和方法)。保持代码的整洁与可维护有一条很简单的规则:

· 10:包内的类不超过10个

· 50:方法的代码行数不超过50

· 500:类的代码行数不超过500

SOLID设计准则

SOLID是Robert Martin提出的一套设计准则的简称。根据他的准则:

一个类应当有仅只有一个任务/职责。执行多个任务的类会让人觉得困惑。

设计模式的使用

设计模式能帮助开发人员更好地在软件中应用软件的设计准则。它还为开发人员提供了跨语言的通用平台。设计模式中的标准术语能让开发人员更容易进行沟通。

关于文档

不要上来就开始写代码。制定计划,准备,编写文档,检查然后再去实现。首先,先把需求记下来。然后去准备设计文档。合理地去假设举证。互相review方案然后进行确认。

使用equals而非==

==是用来比较对象引用的,它会检查两个操作数指向的是不是同一个对象(不是相同的对象,而是同一个对象)。而”equals”则比较的是两个字符串是不是相同(假设是字符串对象)。

避免使用浮点数

只有当确实有必要的时候才使用浮点数。比方说,使用浮点数来表示卢比或者派萨就很容易产生问题——这种情况应当使用BigDecimal。而浮点数更多地是用于测量。

本文来自 Java开发-搁浅 的博客

原创粉丝点击