Java新手问题集锦

Java是目前最流行的编程语言之一——它能够用来编写Windows程序或者是Web应用,移动应用,网络程序,消费电子产品,机顶盒设备,它无处不在。 html

有超过30亿的设备是运行在Java之上的。根据Oracle的统计数据,光是使用中的Java Card就有有50亿。 java

超过900万程序员选择使用Java进行开发,它是最受开发人员欢迎的语言,同时也是最流行的开发平台。 程序员

本文为那些准Java程序员们准备了一系列广为流传的Java最佳编程实践: web

  1. 优先返回空集合而非null

若是程序要返回一个不包含任何值的集合,确保返回的是空集合而不是null。这能节省大量的"if else"检查。 正则表达式

public class getLocationName { return (null==cityName ? "": cityName); }
  1. 谨慎操做字符串

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

//Slower Instantiation String bad = new String("Yet another string object"); //Faster Instantiation String good = "Yet another string object"
  1. 避免无用对象

建立对象是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; } }
  1. 数组与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]; } }
  • 数组是定长的,而ArrayList是变长的。因为数组长度是固定的,所以在声明数组时就已经分配好内存了。而数组的操做则会更快一些。另外一方 面,若是咱们不知道数据的大小,那么过多的数据便会致使ArrayOutOfBoundException,而少了又会浪费存储空间。
  • ArrayList在增删元素方面要比数组简单。
  • 数组能够是多维的,但ArrayList只能是一维的。
  1. try块的finally块没有被执行

看下下面这段代码: json

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块中的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."); } } } }
  1. 判断奇数

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

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

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

代码能够修改为这样:

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

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

  1. 单引号与双引号的区别
public class Haha { public static void main(String args[]) { System.out.print("H" + "a"); System.out.print('H' + 'a'); } }

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

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

内存泄露会致使软件的性能降级。因为Java是自动管理内存的,所以开发人员并无太多办法介入。不过仍是有一些方法可以用来防止内存泄露的。

  • 查询完数据后当即释放数据库链接
  • 尽量使用finally块
  • 释放静态变量中的实例
  1. 避免死锁

死锁出现的缘由有不少。避免死锁不是一句话就能解决的。一般来讲,当某个同步对象在等待另外一个同步对象所拥有的资源上的锁时,便会产生死锁。

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

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

输出:

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..."); } } } } 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...
  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。所以最好检查下对象是否为空以免相似状况。

private int getListOfStudents(File[] files) { if (files == null) throw new NullPointerException("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; 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); } }

输出:

{"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; 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
  1. 简单字符串查找

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

  1. 列出目录下的文件

你能够用下面的代码来列出目录下的文件。这个程序会遍历某个目录下的全部子目录及文件,并存储到一个数组里,而后经过遍历数组来列出全部文件。

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]); } } }
  1. 一个简单的IO程序

Java提供了FileInputStream以及FileOutputStream类来进行文件的读写操做。FileInputStream的构 造方法会接收输入文件的路径做为入参而后建立出一个文件的输入流。一样的,FileOutputStream的构造方法也会接收一个文件路径做为入参而后 建立出文件的输出流。在处理完文件以后,一个很重要的操做就是要记得"close"掉这些流。

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(); } } } }
  1. 在Java中执行某个shell命令

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

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(); } } }
  1. 使用正则

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

字符

x 字符x
\ 反斜杠
\0n 8进制值为0n的字符(0<=n<=7)
\0nn
\0mnn 8进制值为0mnn的字符(0 <= m <= 3, 0<=n<=7)
\xhh 16进制值为0xhh的字符
\uhhhh 16进制值为0xhhhh的字符
\x{h…h} 16进制值为0xh…h的字符(Character.MINCODEPOINT <= 0xh…h <= Character.MAXCODEPOINT)
\t 制表符(‘\u0009′)
\n 换行符(‘\u000A’)
\r 回车(‘\u000D’)
\f 分页符(‘\u000C’)
\a 警告符(‘\u0007′)
\e ESC(‘\u001B’)
\cx ctrl+x

字符分类

[abc] a, b或c
[^abc] abc之外的任意字符
[a-zA-Z] a到z以及A到Z
[a-d[m-p]] a到d或者m到p[a-dm-p]则是取并集
[a-z&&[def]] d,e或f(交集)
[ad-z]
[a-z&&[^bc]] a到z但不包括b和c
[a-z&&[^m-p]] a到z但不包括mp:也就是[a-lq-z]

预约义字符

. 任意字符,有可能包括换行符
\d 0到9的数字
\D 0到9之外的字符
\s 空格符[ \t\n\x0B\f\r]
\S 非空格符[^\s]
\w 字母[a-zA-Z_0-9]
\W 非字母[^\w]

边界匹配

^ 行首
$ 行末
\b 单词边界
\A 输入的起始位置
\G 前一个匹配的末尾
\Z 输入的结束位置,仅用于最后的结束符
\z 输入的结束位置
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; } }
  1. Java Swing的简单示例

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

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(); } }
  1. 使用Java播放音频

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

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

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(300, 200); 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(); } }
  1. 导出PDF文件

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

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(); } }
  1. 邮件发送

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

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(); } } }
  1. 计算时间

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

currentTimeMillis():返回当前时间自新纪元时间以来的毫秒值,long类型。

long startTime = System.currentTimeMillis(); long estimatedTime = System.currentTimeMillis() - startTime;

nanoTime():返回系统计时器当前的精确时间,纳秒值,这也是long类型。nanoTime()主要是用于计算相对时间而非绝对时间。

long startTime = System.nanoTime(); long estimatedTime = System.nanoTime() - startTime;
  1. 图片缩放

图片缩放能够经过AffineTransform来完成。首先要生成一个输入图片的图片缓冲,而后经过它来渲染出缩放后的图片。

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(100, 100, BufferedImage.TYPE_INT_RGB); Graphics2D g = imgDestination.createGraphics(); AffineTransform affinetransformation = AffineTransform.getScaleInstance(2, 2); g.drawRenderedImage(imgSource, affinetransformation); ImageIO.write(imgDestination, "JPG", new File("outImage.jpg")); } }
  1. 捕获鼠标动做

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

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(500, 500); 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) {} }
  1. FileOutputStream Vs. FileWriter

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

使用FileOutputStream:

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

使用FileWriter:

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

根据Java的接口规范:

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

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

附加建议

  1. 集合的使用

Java提供了许多集合类——好比,Vector,Stack,Hashtable等。因此鼓励开发人员尽量地使用这些集合类有以下缘由:

  • 使用集合使得代码的可重用度更高。
  • 集合类使得代码的结构更良好,更易于理解与维护。
  • 最重要的是这些集合类都通过充分的测试,代码质量很高。
  1. 1-50-500规则

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

  • 10:包内的类不超过10个
  • 50:方法的代码行数不超过50
  • 500:类的代码行数不超过500
  1. SOLID设计准则
  2. SOLID是Robert Martin提出的一套设计准则的简称。根据他的准则:
一个类应当有仅只有一个任务/职责。执行多个任务的类会让人以为困惑。
单一职责原则
开闭原则 开发人员应当优先考虑扩展示有的软件功能,而不是是修改它。
里氏替换原则 子类必须可以替换掉他们的父类型
接口隔离原则 和单一职责原则相似,但它特指的是接口层。每一个接口都应当只负责一项任务。
依赖反转原则 依赖抽象而不是具体实现。也就是说每一个模块都应当经过一个抽象层与其它模块进行解耦。
  1. 设计模式的使用

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

  1. 关于文档

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

  1. 使用equals而非==

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

  1. 避免使用浮点数

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

学习Java的一些资源

最后我想给你们推荐一下学习Java的一些相关资料

原创文章转载请注明出处:Java新手问题集锦

英文原文连接

相关文章
相关标签/搜索