java 7 的新特性

二進制前綴0b或者0B

Java 7 中,整數類型(byte, short, int以及long) 可使用二進制數系來表示。要指定一個二進制字面量,能夠給二進制數字添加前綴 0b 或者 0B。html

public static void main(String[] args) {
    byte a = 0b11;
    short b = 0b11;
    int c = 0b11;
    long d = 0b11;
    System.out.println(a);
    System.out.println(b);
    System.out.println(c);
    System.out.println(d);
}

字面常量數字的下劃線

用下劃線鏈接整數提高其可讀性,自身無含義,不可用在數字的起始和末尾。java

public static void main(String[] args)
{
    long a = 2_147_483_648L;
    int b =0b0001_0010_0110;
    System.out.println(a);
    System.out.println(b);
}

捕獲多個異常

單個catch中捕獲多個異常類型(用|分割)並經過改進的類型檢查從新拋出異常)。算法

Java 7以前的版本

try{
	......   
}catch (IOException ex) {
     logger.error(ex);
     throw new MyException(ex.getMessage());
catch (SQLException ex) {
     logger.error(ex);
     throw new MyException(ex.getMessage());
}catch (Exception ex) {
     logger.error(ex);
     throw new MyException(ex.getMessage());
}

Java 7 的版本

try{
	......    
}catch(IOException | SQLException | Exception ex){
     logger.error(ex);
     throw new MyException(ex.getMessage());
}

【摘自】 http://www.importnew.com/7015.htmlapi

try-with-resources

不須要使用finally來保證打開的流被正確關閉。數組

傳統的資源關閉方式

爲了確保外部資源必定要被關閉,一般關閉代碼被寫入finally代碼塊中,固然咱們還必須注意到關閉資源時可能拋出的異常,因而變有了下面的經典代碼:oracle

public static void main(String[] args) {
    FileInputStream inputStream = null;
    try {
        inputStream = new FileInputStream(new File("E:\\test.txt"));
        ...
    } catch (IOException e) {
        throw new RuntimeException(e.getMessage(), e);
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();//關閉資源時可能拋出的異常
            } catch (IOException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
    }
}

Java 7 的資源關閉方式

將外部資源的句柄對象的建立放在try關鍵字後面的括號中,當這個try-catch代碼塊執行完畢後,Java會確保外部資源的close方法被調用。框架

public static void main(String[] args) {
    try (FileInputStream inputStream = new FileInputStream(new File("E:\\test.txt"))) {
        ...
    } catch (IOException e) {
        throw new RuntimeException(e.getMessage(), e);
    }
}

【摘自】 http://www.javashuo.com/article/p-gxawejwn-hv.html異步

switch 支持String類型

在Java 7 以前,switch 只能支持 byte、short、char、int 這幾個基本數據類型和其對應的封裝類型。switch後面的括號裏面只能放int類型的值,但因爲byte,short,char類型,它們會 自動 轉換爲int類型(精精度小的向大的轉化),因此它們也支持 。socket

注意: 對於精度比int大的類型,好比long、float,doulble,不會自動轉換爲int,若是想使用,就必須強轉爲int,如(int)float。ide

Java 7 後,整形、枚舉類型、boolean和字符串均可以。

public class TestString {
    static String string = "123";
    public static void main(String[] args) {
        switch (string) {
        case "123":
            System.out.println("123");
            break;
        case "abc":
            System.out.println("abc");
            break;
        default:
            System.out.println("defauls");
            break;
        }
    }
}

【摘自】 http://www.javashuo.com/article/p-amiizzgi-go.html

泛型實例化類型自動推斷

Java 7 之前的版本

Map<String, String> myMap = new HashMap<String, String>();

Java 7 的版本

Map<String, String> myMap = new HashMap<>();    //注意後面的"<>"

在這條語句中,編譯器會根據變量聲明時的泛型類型自動推斷出實例化HashMap時的泛型類型。再次提醒必定要注意new HashMap後面的<>,只有加上這個<>才表示是自動類型推斷。

【摘自】 https://blog.csdn.net/u011240877/article/details/47702745

Files工具類和Path接口

java 7 引入了 FIles 類和 Path 接口。他們兩封裝了用戶對文件的全部可能的操做,相比於以前的File類來講,使用起來方便不少。可是其實一些本質的操做仍是很相似的。主要須要知道的是,Path表示路徑可使文件的路徑也能夠是目錄的路徑,Files中全部成員都是靜態方法,經過路徑實現了對文件的基本操做。

Files的簡介

Files類是很是好用的io操做工具類,它提供了不少方法進行一些經常使用的io操做,例如文件複製,移動,刪除,讀取文件內容,寫入文件內容等 。這裏對Files再也不贅述,讀者可查閱相關的文檔:https://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html

Path和File的對比

1. 在錯誤處理方面

java.io.File類裏面不少方法失敗時沒有異常處理,或拋出異常,例如:

public static void main(String[] args) {  
    File file = new File("H://afile"); //This path does not exsit in file system.
    if(!file.delete()){
        System.out.println("刪除失敗");
    }
}

運行結果:

刪除失敗

java.io.File.delete()方法返回一個布爾值指示成功或失敗可是沒有失敗緣由。而java.nio.file.Files.delete(Path)會拋出:NoSuchFileException,DirectoryNotEmptyException,IOException,SecurityException,這樣當刪除一個文件失敗時能夠根據異常來查找失敗緣由。例如:

public static void main(String[] args) throws IOException {  
    Path path = Paths.get("H://afile"); //This path does not exsit in file system.  
    Files.delete(path); 
}

 運行結果:

Exception in thread "main" java.nio.file.NoSuchFileException: H:\afile
	at sun.nio.fs.WindowsException.translateToIOException(Unknown Source)
	at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
	at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
	at sun.nio.fs.WindowsFileSystemProvider.implDelete(Unknown Source)
	at sun.nio.fs.AbstractFileSystemProvider.delete(Unknown Source)
	at java.nio.file.Files.delete(Unknown Source)
	at bin.main(bin.java:10
2. 讀取文件屬性相關

File類中讀取文件屬性都是一個方法返回一個屬性值,而沒有可以直接一次返回不少屬性的方法,形成訪問文件屬性時效率的問題。例如:

public static void main(String[] args) throws IOException {  
        File file = new File("C:\\Users\\liutaigang\\Desktop\\java各個版本的新特性\\javacode\\test.txt");  
        System.out.println("isDirectory:" + file.isDirectory());  
        System.out.println("isHidden:" + file.isHidden());  
        System.out.println("canRead:" + file.canRead());  
        System.out.println("canWrite:" + file.canWrite());  
        System.out.println("lastModified:" + file.lastModified());  
        System.out.println("length:" + file.length());  
  }

打印結果:

isDirectory:false
isHidden:false
canRead:true
canWrite:true
lastModified:1534155733866
length:0

可是對於Java 7中能夠批量讀取文件屬性,並且能夠訪問到文件更詳細的屬性。例如:

public static void main(String[] args) throws IOException {  
        Path path = Paths.get("C:\\Users\\liutaigang\\Desktop\\java各個版本的新特性\\javacode\\test.txt");   
        Map<String, Object> map = Files.readAttributes(path, "*", LinkOption.NOFOLLOW_LINKS);  
	    for (String s : map.keySet()) {  
	        System.out.println(s + ":" + map.get(s));  
	    };
	}

打印結果:

lastAccessTime:2018-08-13T10:22:13.866759Z
lastModifiedTime:2018-08-13T10:22:13.866759Z
size:0
creationTime:2018-08-13T10:22:13.866759Z
isSymbolicLink:false
isRegularFile:true
fileKey:null
isOther:false
isDirectory:false

【部分摘自】http://www.javashuo.com/article/p-byxcyvku-c.html

DirectoryStream

使用DirectoryStream,咱們能夠方便的使用for-each語句迭代出一個目錄下的全部條目(包括文件和目錄),也能夠迭代出指定的文件。例如:

public static void main(String[] args) throws IOException {
    	Path path = Paths.get("");
        //get files of all
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
            for (Path entry: stream) {
                System.out.println(entry);
            }
        }
        
        System.out.println("=======================================================");
        
        //get the file that you need
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(path, "*.{c,h,class,java}")) {
            for (Path entry: stream) {
                System.out.println(entry);
            }
        }
    }

而在Java 7 以前,要在某個目錄下得到指定後綴的文件,就有點繁瑣了,例如:

public static void main(String[] args) throws IOException {
    	File file = new File(".");
        File[] fs = file.listFiles();
        for (File f : fs) {       	
            if(f.isFile() && ( f.getName().endsWith(".c") 
            		|| f.getName().endsWith(".h")
            		|| f.getName().endsWith(".class")
            		|| f.getName().endsWith(".java") )
            		){
                System.out.println(f);
            }
        }
    }

【部分摘自】https://docs.oracle.com/javase/7/docs/api/java/nio/file/DirectoryStream.html

WatchService

Java 7 中新增WatchService能夠監控文件的變更信息(監控到文件是修改,新增、刪除等事件;)

其中註冊事件須要的是:

StandardWatchEventKinds.ENTRY_MODIFY,//更新
StandardWatchEventKinds.ENTRY_DELETE,//刪除
StandardWatchEventKinds.ENTRY_CREATE,//建立

示例代碼:

public static void main(String[] args) 
            throws Exception{

        String filePath = ("E:");

        // 獲取文件系統的WatchService對象
        WatchService watchService = FileSystems.getDefault().newWatchService();
        Paths.get(filePath).register(watchService 
                , StandardWatchEventKinds.ENTRY_CREATE
                , StandardWatchEventKinds.ENTRY_MODIFY
                , StandardWatchEventKinds.ENTRY_DELETE);//註冊事件

        while(true)
        {
            // 獲取下一個文件改動事件
            WatchKey key = watchService.take();
            for (WatchEvent<?> event : key.pollEvents()) 
            {
                System.out.println(event.context() +" --> " + event.kind());
            }
            // 重設WatchKey
            boolean valid = key.reset();
            // 若是重設失敗,退出監聽
            if (!valid)  break;
        }
}

當你在 E: 盤下新建一個目錄,並更名爲 「test」 後,再刪除時,會有打印以下信息:

新建文件夾 --> ENTRY_CREATE
新建文件夾 --> ENTRY_DELETE
test --> ENTRY_CREATE
test --> ENTRY_DELETE

【摘自】http://www.cnblogs.com/hwaggLee/p/6552561.html

FileChannel通道獲取

Java 7 的FileChannel類中新增了靜態方法 open(),用於建立一個訪問文件的通道。例如:

public static void main(String[] args) {
		try {
			Path file = Paths.get("E:\\test.txt");

			FileChannel channel = FileChannel.open(file, StandardOpenOption.READ);

			ByteBuffer buffer = ByteBuffer.allocate(1024);
			channel.read(buffer);

			for(byte b : buffer.array())
			{
				System.out.print((char)b);
			}
		} catch (IOException e) {
			System.out.println(e.getMessage());
		}
	}

【詳情請看】https://docs.oracle.com/javase/8/docs/api/java/nio/channels/FileChannel.html

AsynchronousFileChannel

在 Java 7 中 ,AsynchronousFileChannel被添加到Java NIO。AsynchronousFileChannel使讀取數據,使異步地讀寫文件成爲可能。

public static void main(String[] args) throws IOException, InterruptedException {

		Path path = Paths.get("E:\\test.txt");

		AsynchronousFileChannel fileChannel 
			= AsynchronousFileChannel.open(path, StandardOpenOption.READ);

		ByteBuffer buffer = ByteBuffer.allocate(1024);
		long position = 0;

		Future<Integer> operation = fileChannel.read(buffer, position);//異步讀取,不在主線程中

		while (true)
		{
		    if(operation.isDone())//在主線程中判斷是否讀取完成
		    {
		    	buffer.flip();
				byte[] data = new byte[buffer.limit()];
				buffer.get(data);
				System.out.println(new String(data));
				buffer.clear();
				break;
		    }
		    else
		    {
		    	System.out.println("loading...");
		    }
		}
	}

若是使用傳統的方法(java 7 以前)實現上述的功能,會比較複雜。請看示例:

/*
     * 回調接口的定義,由須要異步回調的類實現
     */
    public interface CallBack {
    	// 當異步線程完成時,調用此方法
    	public void Done();
    }

public class MainThread implements CallBack {
    	private ReadThread readThread;
    	
    	public Boolean isDone = false;//異步線程的完成標識,false--未完成,true--已完成
    	
        public MainThread(ReadThread readThread) {
            this.readThread = readThread;
        }
     
        public void readFile(){
            new Thread(new Runnable() {
                [@Override](https://my.oschina.net/u/1162528)
                public void run() {
                	readThread.readFileContent(MainThread.this);
                }
            }).start();
        }
     
        [@Override](https://my.oschina.net/u/1162528)
        public void Done() {
            this.isDone = true;
        }  
    }

public class ReadThread {
    	private File file;
    	private byte[] buf;
    	
    	public ReadThread(File file, byte[] buf)
    	{
    		this.file = file;
    		this.buf = buf;
    	}
    	
    	public void readFileContent(CallBack callBack) {
    		InputStream input = null;
    		try {
    			input = new FileInputStream(file);
    			input.read(buf);
    		} catch (IOException e) {
    			e.printStackTrace();
    		} finally
    		{
    			try {
    				if(null != input) input.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		
    		callBack.Done();//通知已完成
    	}
    }

public class Test {
    	public static void main(String[] args) {
    		File file = new File("E:\\test.txt");
    		byte[] buf = new byte[1024];
    		
    		ReadThread readThread = new ReadThread(file, buf);
    		MainThread mainThread = new MainThread(readThread);
    		mainThread.readFile();
    		
    		//等待異步線程完成
    		while(true)
    		{
    			if(mainThread.isDone)
    			{
    				for(byte b : buf)
    				{
    					System.out.print((char)b);
    				}
    				break;
    			}
    			else
    			{
    				System.out.println("loading...");
    			}
    		}
    	}
    }

【部分摘自】

https://www.jianshu.com/p/b38f8c596193

https://blog.csdn.net/wanglha/article/details/51383245

NetworkChannel接口

NetworkChannel是 Java 7 中新增的NIO.2中的接口,ServerSocketChannel,SocketChannel和DatagramChannel 都實現了這個接口。NetworkChannel加入讓咱們對channel控制的更細膩,能夠對本地網卡作詳細的檢索。

public static void main(String[] args) throws IOException {
		SelectorProvider provider = SelectorProvider.provider();
		try {
			NetworkChannel socketChannel = provider.openSocketChannel();
			SocketAddress address = new InetSocketAddress(3080);
			socketChannel = socketChannel.bind(address);

			Set<SocketOption<?>> socketOptions = socketChannel.supportedOptions();
			System.out.println(socketOptions.toString());

			socketChannel.setOption(StandardSocketOptions.IP_TOS, 3);
			System.out.println(socketChannel.getOption(StandardSocketOptions.IP_TOS));
			Boolean keepAlive = socketChannel.getOption(StandardSocketOptions.SO_KEEPALIVE);
			System.out.println(keepAlive);

		} catch (IOException e) {
			System.out.println(e.getMessage());
		}
	}

【部分摘自】https://www.cnblogs.com/pony1223/p/8186229.html?utm_source=debugrun&utm_medium=referral

新增Fork/Join框架

什麼是Fork/Join框架

java 7 加入了並行計算的框架Fork/Join,Fork/Join採用的是分治法。所謂分治法就是將一個大任務切分紅N個小任務並行執行,並最終聚合結果。 在實際狀況中,不少時候咱們都須要面對經典的「分治」問題。要解決這類問題,主要任務一般被分解爲多個任務塊(分解階段),其後每一小塊任務被獨立並行計算。一旦計算任務完成,每一塊的結果會被合併或者解決(解決階段) 。

請看圖:

Fork/Join框架的核心類

1. ForkJoinPool

這個類實現了ExecutorService接口和工做竊取算法(Work-Stealing Algorithm)。它管理工做者線程,並提供任務的狀態信息,以及任務的執行信息。

2. ForkJoinTask

這個類是一個在ForkJoinPool中執行的任務的基類。ForkJoinTask 提供了在一個任務裏執行 fork() 和 join() 操做的機制和控制任務狀態的方法。一般,爲了實現Fork/Join任務,須要實現它的子類:RecursiveAction、RecursiveTask。

  • RecursiveAction:用於任務沒有返回結果的場景。
  • RecursiveTask:用於任務有返回結果的場景。

它們的繼承(實現)關係圖:

簡單的例子

在這個例子中,會使用ExecutorService的方法和Fork/Join的方法來共同實現一個任務——1~1000的累加和。

1. Java 7 以前——ExecutorService
public class ExecutorServiceCalculator {
    private int parallism;
    private ExecutorService pool;

    public ExecutorServiceCalculator() {
        parallism = Runtime.getRuntime().availableProcessors(); // 獲取CPU的核心數
        pool = Executors.newFixedThreadPool(parallism);
    }

    private class SumTask implements Callable<Integer> {
        private Integer[] numbers;
        private int from;
        private int to;

        public SumTask(Integer[] numbers, int from, int to) {
            this.numbers = numbers;
            this.from = from;
            this.to = to;
        }

        [@Override](https://my.oschina.net/u/1162528)
        public Integer call() throws Exception {
            int total = 0;
            for (int i = from; i <= to; i++) {
                total += numbers[i];
            }
            return total;
        }
    }

    /**
     * 計算入口
     * [@param](https://my.oschina.net/u/2303379) numbers 用於計算的數組
     * [@return](https://my.oschina.net/u/556800) 最終的計算結果
     */
    public int sumUp(Integer[] numbers) {
        List<Future<Integer>> results = new ArrayList<>();

        // 把任務分解爲 n 份,交給 n 個線程處理
        int part = numbers.length / parallism;
        for (int i = 0; i < parallism; i++) {
            int from = i * part;
            int to = (i == parallism - 1) ? numbers.length - 1 : (i + 1) * part - 1;
            results.add(pool.submit(new SumTask(numbers, from, to)));
        }

        // 把每一個線程的結果相加,獲得最終結果
        int total = 0;
        for (Future<Integer> f : results) {
            try {
                total += f.get();
            } catch (Exception ignore) {}
        }
        return total;
    }
    
    /**
     * 當全部線程任務完成時,關閉計算器(Calculator)
     */
    public void shutDown(){
    	this.pool.shutdown();
    };
}

public class Test {

	static final int TOTAL = 1000;
	
	public static void main(String[] args) {
		
		ExecutorServiceCalculator esc = new ExecutorServiceCalculator();
		
		Integer[] numbers = new Integer[TOTAL];
		for(int i=0; i<TOTAL; i++){
			numbers[i] = Integer.valueOf(i+1);
		}
		
		int sum = 0;
		sum = esc.sumUp(numbers);
		esc.shutDown();
		System.out.println("ExecutorServiceCalculator's result :" + sum);	
	}
}
2. java 7的版本 ——Fork/Join
public class ForkJoinCalculator {
    private ForkJoinPool pool;

    public ForkJoinCalculator() {
        pool = new ForkJoinPool();//會以Runtime.avaliableProcessors()方法的返回值做爲並行線程數量參數
    }
    
    private class SumTask extends RecursiveTask<Integer> {
        private Integer[] numbers;
        private int from;
        private int to;
        private int threshold;//最小任務的計算量(臨界值)

        public SumTask(Integer[] numbers, int from, int to, int threshold) {
            this.numbers = numbers;
            this.from = from;
            this.to = to;
            this.threshold = threshold;
        }

        [@Override](https://my.oschina.net/u/1162528)
        protected Integer compute() {
            // 當須要計算的數字小於threshold時,直接計算結果
            if (to - from < threshold) {
            	int total = 0;
                for (int i = from; i <= to; i++) {
                    total += numbers[i];
                }
                return total;
            // 不然,把任務一分爲二,遞歸計算
            } else {
                int middle = (from + to) / 2;
                SumTask taskLeft = new SumTask(numbers, from, middle, threshold);
                SumTask taskRight = new SumTask(numbers, middle+1, to, threshold);
                taskLeft.fork();
                taskRight.fork();
                return taskLeft.join() + taskRight.join();
            }
        }
    }


    /**
     * 計算入口
     * [@param](https://my.oschina.net/u/2303379) numbers 用於計算的數組
     * @param threshold 最小任務的計算量(臨界值)
     * @return 最終的計算結果
     * @throws InterruptedException
     * @throws ExecutionException
     */
    public int sumUp(Integer[] numbers, int threshold) 
    		throws InterruptedException, ExecutionException {
    	
        return pool.submit(new SumTask(numbers, 0, numbers.length-1, threshold)).get();
    }
    
    /**
     * 當全部線程任務完成時,關閉計算器(Calculator)
     */
    public void shutDown(){
    	this.pool.shutdown();
    }
}

public class Test {

	static final int TOTAL = 1000;
	
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		
		ForkJoinCalculator fjc = new ForkJoinCalculator();
		
		Integer[] numbers = new Integer[TOTAL];
		for(int i=0; i<TOTAL; i++){
			numbers[i] = Integer.valueOf(i+1);
		}
		
		int sum = 0;
		sum = fjc.sumUp(numbers, 50);
		fjc.shutDown();
		System.out.println("ForkJoinCalculator's result :" + sum);	
	}
}

【摘自】

https://blog.csdn.net/caicongyang/article/details/51180330

http://www.importnew.com/2279.html

https://blog.csdn.net/al_assad/article/details/60878486

http://blog.dyngr.com/blog/2016/09/15/java-forkjoinpool-internals/

相關文章
相關標籤/搜索