java是目前最流行的編程語言之一——它可以用來編寫Windows程序或者是Web應用,移動應用,網絡程序,消費電子產品,機頂盒設備,它無處不在。
有超過30億的設備是運行在Java之上的。根據Oracle的統計數據,光是使用中的Java Card就有有50億。
超過900萬程序員選擇使用Java進行開發,它是最受開發人員歡迎的語言,同時也是最流行的開發平臺。
本文為那些準Java程序員們準備了一系列廣為流傳的Java最佳編程實踐
如果程序要返回一個不包含任何值的集合,確保返回的是空集合而不是null。這能節省大量的”if else”檢查。
public class getLocationName { return (null==cityName ? "": cityName);}
如果兩個字符串在for循環中使用+操作符進行拼接,那么每次循環都會產生一個新的字符串對象。這不僅浪費內存空間同時還會影響性能。類似的,如果初始化字符串對象,盡量不要使用構造方法,而應該直接初始化。比方說:
//Slower InstantiationString bad = new String("Yet another string object");//Faster InstantiationString good = "Yet another string object"
創建對象是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; }}
開發人員經常會發現很難在數組和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]; }}
看下下面這段代碼:
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了??赡苁荢ystem.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."); } } }}
看下這幾行代碼,看看它們是否能用來準確地判斷一個數是奇數?
public boolean oddOrNot(int num) { return num % 2 == 1;}
看似是對的,但是每執行四便會有一個錯誤的結果(用數據說話)。考慮到負奇數的情況,它除以2的結果就不會是1。因此,返回值是false,而這樣是不對的。
代碼可以修改成這樣:
public boolean oddOrNot(int num) { return (num & 1) != 0;}
這么寫不光是負奇數的問題解決了,并且還是經過充分優化過的。因為算術運算和邏輯運行要比乘除運算更高效,計算的結果也會更快。
public class Haha { public static void main(String args[]) { System.out.print("H" + "a"); System.out.print('H' + 'a'); }}
看起來這段代碼會返回”Haha”,但實際返回的是Ha169。原因就是用了雙引號的時候,字符會被當作字符串處理,而如果是單引號的話,字符值會通過一個叫做基礎類型拓寬的操作來轉換成整型值。然后再將值相加得到169。
內存泄露會導致軟件的性能降級。由于Java是自動管理內存的,因此開發人員并沒有太多辦法介入。不過還是有一些方法能夠用來防止內存泄露的。
死鎖出現的原因有很多。避免死鎖不是一句話就能解決的。通常來說,當某個同步對象在等待另一個同步對象所擁有的資源上的鎖時,便會產生死鎖。
試著運行下下面的程序。它會告訴你什么是死鎖。這個死鎖是由于兩個線程都在等待對方所擁有的資源,因此會產生死鎖。它們會一直等待,沒有誰會先放手。
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: 13Subtraction Thread: 7Holding 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: 13Holding First Lock...Addition Thread: Waiting for AddLock...Threads: Holding Add and Sub Locks...Subtraction Thread: 7Holding Second Lock...Subtraction Thread: Waiting for SubLock...Threads: Holding Add and Sub Locks...
某些Java程序是CPU密集型的,但它們會需要大量的內存。這類程序通常運行得很緩慢,因為它們對內存的需求很大。為了能提升這類應用的性能,可得給它們多留點內存。因此,假設我們有一臺擁有10G內存的Tomcat服務器。在這臺機器上,我們可以用如下的這條命令來分配內存:
export JAVA_OPTS="$JAVA_OPTS -Xms5000m -Xmx6000m -XX:PermSize=1024m -XX:MaxPermSize=2048m"
在Java中進行操作計時有兩個標準的方法:System.currentTimeMillis()和System.nanoTime()。問題就在于,什么情況下該用哪個。從本質上來講,他們的作用都是一樣的,但有以下幾點不同:
數據類型 | 所用字節 | 有效位數 |
float | 4 | 7 |
double | 8 | 15 |
在對精度要求高的場景下,double類型相對float要更流行一些,理由如下:
大多數處理器在處理float和double上所需的時間都是差不多的。而計算時間一樣的前提下,double類型卻能提供更高的精度。
Java是通過異或操作來進行冪運算的。Java對于冪運算有兩種處理方式:
double square = double a * double a; // Optimizeddouble cube = double a * double a * double a; // Non-optimizeddouble cube = double a * double square; // Optimizeddouble quad = double a * double a * double a * double a; // Non-optimizeddouble quad = double square * double square; // Optimized
double cube = Math.pow(base, exponent);
不到萬不得已不要使用Math.pow。比方說,當指數是小數的時候。因為Math.pow要比乘積慢300-600倍左右。
空指針異常是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"); }
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"}
開發人員要想解析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 = "http://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: 1The type is: donutThe name is: CakeThe PPU is: 0.55Batters:ID 1001 type RegularID 1002 type ChocolateID 1003 type BlueberryID 1004 type Devil's FoodTopping:ID 5001 type NoneID 5002 type GlazedID 5005 type SugarID 5007 type Powdered SugarID 5006 type Chocolate with SprinklesID 5003 type ChocolateID 5004 type Maple
Java提供了一個庫函數叫做indexOf()。這個方法可以用在String對象上,它返回的是要查找的字符串所在的位置序號。如果查找不到則會返回-1。
你可以用下面的代碼來列出目錄下的文件。這個程序會遍歷某個目錄下的所有子目錄及文件,并存儲到一個數組里,然后通過遍歷數組來列出所有文件。
import java.io.*;public class ListContents { public static void main(String[] args) { File file = new File("http://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]); } }}
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("http://home//user//Documents//InputFile.txt"); out = new FileOutputStream("http://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提供了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(); } }}
正則表達式的結構摘錄如下(來源: 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; } }
有了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 = "http://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 + "http://Image1.jpg"))); myVerticleBox.add(new JButton(new ImageIcon(path + "http://Image2.jpg"))); myVerticleBox.add(new JButton(new ImageIcon(path + "http://Image3.jpg"))); contentPane.add(myHorizontalBox); contentPane.add(myVerticleBox); pack(); setVisible(true); } public static void main(String args[]) { new SwingsDemo(); } }
在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(); }}
將表格導出成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(); } }
在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(); } }}
許多程序都需要精確的時間計量。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;
圖片縮放可以通過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")); }}
實現了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) {}}
在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。
Java提供了許多集合類——比如,Vector,Stack,Hashtable等。所以鼓勵開發人員盡可能地使用這些集合類有如下原因:
在大型軟件系統中,代碼的可維護性是件很有挑戰的工作。新加入的開發人員經常會抱怨這些情況:單片代碼(Monolithic Code),意大利面式代碼(spaghetti code, 常用于描述捆綁在一起并且低內聚的類和方法)。保持代碼的整潔與可維護有一條很簡單的規則:
一個類應當有僅只有一個任務/職責。執行多個任務的類會讓人覺得困惑。
單一職責原則 | |
開閉原則 | 開發人員應當優先考慮擴展現有的軟件功能,而不是是修改它。 |
里氏替換原則 | 子類必須能夠替換掉他們的父類型 |
接口隔離原則 | 和單一職責原則類似,但它特指的是接口層。每個接口都應當只負責一項任務。 |
依賴反轉原則 | 依賴抽象而不是具體實現。也就是說每個模塊都應當通過一個抽象層與其它模塊進行解耦。 |
設計模式能幫助開發人員更好地在軟件中應用軟件的設計準則。它還為開發人員提供了跨語言的通用平臺。設計模式中的標準術語能讓開發人員更容易進行溝通。
不要上來就開始寫代碼。制定計劃,準備,編寫文檔,檢查然后再去實現。首先,先把需求記下來。然后去準備設計文檔。合理地去假設舉證?;ハ鄏eview方案然后進行確認。
==是用來比較對象引用的,它會檢查兩個操作數指向的是不是同一個對象(不是相同的對象,而是同一個對象)。而”equals”則比較的是兩個字符串是不是相同(假設是字符串對象)。
只有當確實有必要的時候才使用浮點數。比方說,使用浮點數來表示盧比或者派薩就很容易產生問題——這種情況應當使用BigDecimal。而浮點數更多地是用于測量。
新聞熱點
疑難解答