[轉載] Java7中增加的新特性

ey_snail發表於2020-12-24

參考連結: Java多捕獲Multicatch

Java7語言,語法的變化 

1、switch語句中的String 

在Java6及之前,case語句中的常量只能是byte,char,short和int(也可以是對應的封裝型別Byte,Character,Short和Integer)或列舉常量。Java7中增加了String 

public static void main(String[] args) {

    TestSwitchUseString("1");

    TestSwitchUseString("2");

    TestSwitchUseString("");

}

 

public static void TestSwitchUseString(String str){

    switch (str) {

    case "1":

        System.out.println("It's Monday");

        break;

    case "2":

        System.out.println("It's Tuesday");

        break;

    default:

        System.out.println("It's Default");

        break;

    }

2、更強的數字文字表示法 

二進位制文字再也不用這樣去轉換 int x = Integer.parseInt("1100110",2);  在Java7中可以直接這樣寫: int x = 0b1100110; 

可以用下劃線(_)作數字的分隔符,為了閱讀數字更容易,Java在編譯時會去掉下劃線。  如 long num = 3_456_231_890L; 

3、改善後的異常處理 

multicatch  這是在Java6及之前的處理方式: 

public Configuration getConfig(String fileName) {

    Configuration cfg = null;

    try {

       String fileText = getFile(fileName);

       cfg = verifyConfig(parseConfig(fileText));

    } catch (FileNotFoundException fnfx) {

       System.err.println("Config file '" + fileName + "' is missing");

    } catch (IOException e) {

       System.err.println("Error while processing file '" + fileName + "'");

    } catch (ConfigurationException e) {

       System.err.println("Config file '" + fileName + "' is not consistent");

    } catch (ParseException e) {

       System.err.println("Config file '" + fileName + "' is malformed");

    }

 

    return cfg;

現在利用multicatch可以在一個catch中處理多個異常 

public Configuration getConfig(String fileName) {

    Configuration cfg = null;

    try {

       String fileText = getFile(fileName);

       cfg = verifyConfig(parseConfig(fileText));

    } catch (FileNotFoundException | ParseException | ConfigurationException e) {

       System.err.println("Config file '" + fileName

           + "' is missing or malformed");

    } catch (IOException iox) {

       System.err.println("Error while processing file '" + fileName + "'");

    }

 

    return cfg;

final重拋 

catch(final Exception e){... throw e} 

關鍵字final 表明實際丟擲的異常就是執行時遇到的異常,這樣就不會丟擲籠統的異常型別,從而避免在上層只能用籠統的catch捕獲。 

try-with-resources(TWR)  Java6及之前的資源要自己在finaly中關閉而在Java7中可以實現資源自動關閉 如: 

try(OutputStream out = new FileOutputStream(file); InputStream is = url.openStream()){

    byte[] buf = new byte[4096];

    int len;

    while((len= is.read(buf))>0){

        out.write(buf,0,len);

    }

這是資源自動化管理程式碼塊的基本形式—-把資源放在try的圓括號內。要確保try-with-resources生效,正確的用法是為各個資源宣告獨立變數。因為巢狀宣告的話,java編譯器可能不能正確按順序釋放相關資源。目前TWR特性依靠一個新定義的介面實現AutoCloseable.TWR的try從句中出現的資源類必須實現這個介面,Java7平臺的大多數資源類都被修改過,已經實現了AutoCloseable 

4、鑽石語法 

針對建立泛型定義的例項太過繁瑣的問題,Java7做了一項改進,以減少處理泛型時敲鍵盤的次數。如: 

Map<Integer,Map<String,String>> usersLists = new HashMap<Integer,Map<String,String>>(); 

在Java7中編譯器會推斷出右側的型別資訊 

Map<Integer,Map<String,String>> usersLists = new HashMap<>(); 

5、NIO.2 

5.1、IO發展簡史 

Java1.4中引入NIO增加了以下特性: 

為IO操作抽象出緩衝區和通道層 字符集的編碼和解碼能力 提供了能夠對映為記憶體資料的介面 實現非阻塞IO的能力 基於流行Perl實現的正規表示式類庫 

NIO.2中的目標 

一個能批量獲取檔案屬性的檔案系統介面,去掉和特定檔案系統相關的API,還有一個用於標準檔案系統實現的服務提供介面 提供一個套接字和檔案都能夠進行非同步(與輪詢,非阻塞相對)IO操作的API 完成通道功能,包括額外繫結,選項配置和多播資料包的支援。  

5.2、Path 

關鍵基礎類 

Path —>Path類中的方法可以用來獲取路徑資訊,訪問該路徑中的各元素,將路徑轉換為其他形式,或提取路徑中的一部分。有的方法還可以匹配路徑字串以及移除路徑中的冗餘項Paths —>工具類,提供返回一個路徑的輔助方法,比如get(String first,String…more)和get(URI uri)FileSystem —>與檔案系統互動的類,無論是預設的檔案系統,還是通過其統一資源標識(URI)獲取的可選檔案系統FileSystems —>工具類,提供各種方法,比如其中用於返回預設檔案系統的FileSystems.getDefault(); 

 

 Path不一定代表真實的檔案或目錄。你可以隨心所欲地操作Path,用Filse中的功能來檢查檔案是否存在,並對它進行處理。Path並不僅限於檔案系統,它也能表示zip或jar這樣的檔案系統。 

 

//預設的獲取Path例項方法

    Path path = Paths.get("/testpath/webmonitor/webmonitor.zip");//  等同於  Path path = FileSystems.getDefault().getPath("/testpath/webmonitor/webmonitor.zip");

    System.out.println("FileName:"+path.getFileName());

    System.out.println("Number of Name element:"+path.getNameCount());//路徑名字分段個數

    System.out.println("Parent path:"+path.getParent() );

    System.out.println("Root path:"+ path.getRoot());

    System.out.println("SubPath from root:" + path.subpath(0, 1));

 

    path.normalize();//去掉冗餘的資訊

    System.out.println(path.toAbsolutePath());//獲取絕對路徑

    try {

        path.toRealPath();//這個是真實對映到實際物理硬碟上的路徑

    } catch (IOException e) {

        e.printStackTrace();

    }

 

    //取得兩個path之間的路徑差

    Path testPath = Paths.get("/testpath/webmonitor");

    Path newPath = testPath.relativize(path);

    System.out.println("newPath:"+newPath);

 

    Path newPath2 = path.relativize(testPath);

    System.out.println("newPath2:"+newPath2);

    //合併path

    Path path1 = Paths.get("/test/");

    Path path2 = Paths.get("path2/file.name");//沒加上“/”表示一個絕對路徑

    Path path3 = path1.resolve(path2);// 等同於 path1.resolve("path2/file.name");

    System.out.println("path3:"+path3); 

5.3、處理目錄和目錄樹 

新引入的java.nio.file.DirectoryStream 介面和它的實現類提供了很多功能: 

迴圈遍歷目錄中的子項,比如查詢目錄中的檔案;用glob表示式(如Foobar)進行目錄子項匹配和基於MIME的內容檢測(如text/xml檔案);glob模式匹配類似於正規表示式,但稍有不同用walkFileTree方法實現遞迴移動,複製和刪除操作 

在目錄中查詢檔案  //查詢trunk工程中所有properties檔案 

Path dir = Paths.get("C:/Users/twang/Desktop/trunk");//設定一個路徑

    try(DirectoryStream<Path> stream = Files.newDirectoryStream(dir,"*.properties")){//返回一個經過過濾的DirectoryStream,其中包含.properties檔案

        for(Path path:stream){

            System.out.println(path.getFileName());

        }

    }catch(IOException e){

        e.printStackTrace();

    } 

//以上程式碼是單個目錄中處理,如果需要遞迴過濾多個目標則用到時目錄樹 

遍歷目錄樹  java7r提供了遍歷目錄樹的功能,其中的關鍵方法是 

Files.walkFileTree(Path startingDir,FileVisitor<? super Path> visitor) 

實現FileVisitor介面比較麻煩,最少要實現下面5個方法(T 一般是path) 

FileVisitResult preVisitDirectory(T dir)FileVisitResult preVisitDirectoryFailed(T dir,IOException exc)FileVisitResult visitFile(T file,BasicFileAttributes attrs)FileVisitResult visitFileFailed(T file,IOException exc)FileVisitResult postVisitDirectory(T dir,IOException exc) 

Java7提供了一個預設的實現 SimpleFileVisitor 

//列印出一個目錄下所有的Java檔名 

private static void getAllJavaFile() {

    Path startDir = Paths.get("D:/tim/newWorkSpace");//設定起始目錄

    try {

        Files.walkFileTree(startDir,new FindJavaVisitor());//呼叫 walkFileTree

    } catch (IOException e) {

        e.printStackTrace();

    }

}

 

private static class FindJavaVisitor extends SimpleFileVisitor<Path>{//擴充套件於SimpleFileVisitor<Path>

 

    @Override

    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)//重寫檔案訪問方法

            throws IOException {

        if(file.toString().endsWith(".java")){

            System.out.println(file.getFileName());

        }

        return FileVisitResult.CONTINUE;//返回繼續掃描的結果

    }

 

5.4、NIO檔案系統IO 

檔案處理基礎類 

Files 可以讓你輕鬆複製,移動,刪除或處理檔案的工具類WatchService 用來監視檔案或目錄的核心類,不管它們有沒有變化 

主要功能有: 

建立和刪除檔案移動,複製,重新命名和刪除檔案檔案屬性的讀寫檔案內容的讀取和寫入處理符號連結用WatchService發出檔案修改通知使用SeekableByteChannel——一個可以指定位置及大小的增強型位元組通道。 

檔案的移動,複製,建立 

//建立一個資料夾和一個檔案

    Path pathDir = Paths.get("d:/myTest");

    Path pathDir2 = Paths.get("d:/myTest2");

    Path pathFile = Paths.get("d:/myTest/test.text");

    try {

        if(!pathDir.toFile().exists()){

            Files.createDirectories(pathDir);

        }

        if(!pathDir2.toFile().exists()){

            Files.createDirectories(pathDir2);

        }

        if(!pathFile.toFile().exists()){

            Files.createFile(pathFile);

        }

        //複製檔案

        Files.copy(pathFile, Paths.get("d:/myTest2/copyTest.text"),StandardCopyOption.REPLACE_EXISTING);

        //移動檔案

        Files.move(pathFile, Paths.get("d:/myTest2/moveTest.text"),StandardCopyOption.REPLACE_EXISTING);

    } catch (IOException e) {

        e.printStackTrace();

    } 

檔案屬性  //獲取檔案相關屬性 

Path pathFile = Paths.get("d:/myTest/test.text");

    try {

        if(!Files.exists(pathFile)){

            Files.createFile(pathFile);

        }

        System.out.println(Files.getLastModifiedTime(pathFile));

        System.out.println(Files.size(pathFile));

        System.out.println(Files.isSymbolicLink(pathFile));

        System.out.println(Files.isDirectory(pathFile));

        System.out.println(Files.readAttributes(pathFile, "*"));//輸出全部屬性

    } catch (IOException e) {

        e.printStackTrace();

    } 

一些相關特定檔案系統的屬性Java7也支援,如隱藏檔案和連結檔案 

利用Files快速讀取寫入檔案 

Path file = Paths.get("d:/myTest/test.text");

    try {

        if(!Files.exists(file)){

                Files.createFile(file);

        }

        //利用傳統IO寫入,讀取

        try(BufferedWriter bw = Files.newBufferedWriter(file, StandardCharsets.UTF_8, StandardOpenOption.APPEND)){

            bw.write("This a test line,This is a test line.");

        }

 

        try(BufferedReader br = Files.newBufferedReader(file, StandardCharsets.UTF_8)){

            String line;

            while((line = br.readLine())!=null){

                System.out.println(line);

            }

        }

 

        //簡化後的讀取和寫入

        List<String> lines = new ArrayList<String>();

        lines.add("\n this is writed by the simplified Files class");

        lines.add("\n this is writed by the simplified Files 222");

 

        Files.write(file, lines, StandardCharsets.UTF_8, StandardOpenOption.APPEND);

 

 

        List<String> list = Files.readAllLines(file, StandardCharsets.UTF_8);

        for(String str:list){

            System.out.println(str);

        }

 

 

    } catch (IOException e) {

        e.printStackTrace();

    } 

檔案修改通知  在Java7中可以用java.nio.file.WatchService類監測檔案或目錄的變化。  //檢測目錄下檔案有沒有被修改 

Path dir = Paths.get("d:/myTest");

    try{

        if(!Files.exists(dir)){

            Files.createDirectories(dir);

        }

 

        WatchService watcher = FileSystems.getDefault().newWatchService();

        //監測變化的key

        WatchKey key = dir.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);

 

        while(true){

            WatchKey keys = watcher.take();

            //得到下一個key的事件

            for(WatchEvent<?> event: keys.pollEvents()){

                //檢測是否為監測事件

                if(event.kind()==StandardWatchEventKinds.ENTRY_MODIFY){

 

                    System.out.println("File have been modified!!"+event.context());

                }

 

            }

            //重新監測事件

            key.reset();

        }

 

    }catch(final Exception e){

        e.printStackTrace();

    } 

SeekableByteChannel  這個介面可能讓開發人員能夠改變位元組通道的位置和大小。JDK中有一個java.nio.channels.SeekableByteChannel介面的實現類—java.nio.channels.FileChannel.這個類可以在檔案讀取或寫入時保持當前位置。它具有定址能力。 

如讀取一個檔案的最後500個字元,在檔案的一個位置覆蓋一些內容 

Path file = Paths.get("d:/myTest/test.text");

    //設定一個緩衝區

    ByteBuffer byteBuffer = ByteBuffer.allocate(512);

    try {

        //開啟相關檔案的FileChannel

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

        //讀取檔案最後500個字元到緩衝區

        channel.read(byteBuffer, channel.size()-500);

        //列印出讀取的字元

        System.out.println(new String(byteBuffer.array()));

 

        //從倒數200的位置寫入我的字元  寫入會覆蓋原來的相應位置字元的

        String str = "****This inserted string********";

        ByteBuffer bb = ByteBuffer.wrap(str.getBytes());

        channel.write(bb, channel.size()-200);

 

        //再讀取檔案最後500個字元到緩衝區

        byteBuffer.flip();//清除快取內容

        channel.read(byteBuffer, channel.size()-500);

        //再列印出讀取的字元

        System.out.println(new String(byteBuffer.array()));

 

    } catch (IOException e) {

        e.printStackTrace();

    } 

5.5、非同步IO 

非同步IO是一種在讀寫操作結束前允許進行其他操作的IO處理 

Java7的三個新的非同步通道: 

AsynchronousFileChannel —-用於檔案IOAsynchronousSocketChannel —-用於套接字IO,支援超時AsynchronousServerSocketChannel —-用於套接字接受非同步連線 

使用新的非同步IO api時,主要有兩種形式,將來式和回撥式 

將來式  將來式用現有的Java.util.concurrent技術宣告一個Future,用來儲存非同步操作的處理結果。通常用Future get()方法(帶或不帶超時引數)在非同步IO操作完成時獲取其結果。 

AsynchronousFileChannel會關聯執行緒池,它的任務是接收IO處理事件,並分發給負責處理通道中IO操作結果的結果處理器。跟通道中發起的IO操作關聯的結果處理器確保是由執行緒池中的某個執行緒產生。 

try{

        Path path = Paths.get("D:/迅雷下載/ideaIU-14.0.3.exe");

        //非同步開啟檔案,用後臺執行緒

        AsynchronousFileChannel channel = AsynchronousFileChannel.open(path);

        //讀取100000000位元組,採取併發處理

        ByteBuffer buffer = ByteBuffer.allocate(100_000_000);

        Future<Integer> result = channel.read(buffer, 0);

 

        while(!result.isDone()){

            //可以做點其它事情

            System.out.println("Have not reading finish....,I can do some other things");

        }

        //獲取結果

        Integer byteRead = result.get();

        System.out.println("Finish reading:"+byteRead);

    }catch(Exception e){

        e.printStackTrace();

    } 

回撥式  回撥式所採用的事件處理技術類似於Swing UI程式設計採用的機制。基本思想是主執行緒會派一個偵查員CompletionHandler到獨立的執行緒中執行IO操作。這個偵查員將帶著IO的操作的結果返回到主執行緒中,這個結果會觸發它自己的completed或failed方法(要重寫這兩個方法)。在非同步IO活動結束後,介面java.nio.channels.CompletionHandler會被呼叫,其中V是結果型別,A是提供結果的附著物件。此時必須已經有了該介面completed(V,A)和failed(V,A)方法的實現,你的程式才能知道非同步IO操作成功或失敗時該如何處理。 

try{

        Path path = Paths.get("D:/迅雷下載/ideaIU-14.0.3.exe");

        //非同步開啟檔案,用後臺執行緒

        AsynchronousFileChannel channel = AsynchronousFileChannel.open(path);

        //讀取100000000位元組,非同步回撥處理

        ByteBuffer buffer = ByteBuffer.allocate(100_000_000);

        channel.read(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() {

 

            //讀取完成時的回撥方法

            @Override

            public void completed(Integer result, ByteBuffer attachment) {

                System.out.println("Have read file finished:"+result);

            }

            //

            @Override

            public void failed(Throwable exc, ByteBuffer attachment) {

                System.out.println("Read file failed:");

                exc.printStackTrace();

 

            }

 

        });

 

        System.out.println("Main thread can do something-----");

 

    }catch(Exception e){

        e.printStackTrace();

    } 

將來式和回撥式的非同步訪問同樣適用於AsynchronousServerSocketChannel和AsynchronousSocketChannel。我們可以用它們編寫程式來處理網路套接字,比如語音IP。 

5.6、Socket和Channel的整合 

Java7推出了NetworkChannel,把Socket和Channel結合到一起。 

java.nio.channels包 定義通道,表示連線到執行IO操作的實體,比如檔案和套接字,定義用於多路傳輸,非阻塞IO操作的選擇器java.net.Socket類 該類實現了客戶端套接字,套接字是兩個機器間通訊的端點。 

NetworkChannel  新介面java.nio.channels.NetworkChannel代表一個連線到網路套接字通道的對映。 

SelectorProvider provider = SelectorProvider.provider();

    try{

        //將NetworkChannel繫結到3999埠上

        NetworkChannel socketChannel = provider.openSocketChannel();

        SocketAddress address = new InetSocketAddress(3999);

        socketChannel = socketChannel.bind(address);

        //檢查套接字選項

        Set<SocketOption<?>> socketOptions = socketChannel.supportedOptions();

        System.out.println(socketOptions.toString());

        //設定套接字Tos(服務條款)選項

        socketChannel.setOption(StandardSocketOptions.IP_TOS, 3);

        //獲取SO_KEEPALIVE選項

        Boolean keepAlive = socketChannel.getOption(StandardSocketOptions.SO_KEEPALIVE);

    }catch(Exception e){

        e.printStackTrace();

    } 

MulticastChannel  利用它可以實現多播功能,為了讓新來的NetworkChannel加入多播組,Java7提供了一個新介面java.nio.channels.MulticastChannel及其預設實現類DatagramChannel.你可以很輕鬆地對多播傳送和接收資料。 

try {

        //選擇網路埠

        NetworkInterface networkInterface = NetworkInterface.getByName("net1");

        //開啟DatagramChannel

        DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET);

        //將通道設定為多播

        dc.setOption(StandardSocketOptions.SO_BROADCAST, true);

        dc.bind(new InetSocketAddress(8080));

        dc.setOption(StandardSocketOptions.IP_MULTICAST_IF, networkInterface);

        //加入多播組

        InetAddress group = InetAddress.getByName("127.0.0.1");

        MembershipKey key = dc.join(group, networkInterface);

 

    } catch (Exception e) {

        e.printStackTrace();

    } 

轉載自:  http://wn398.github.io/2014/04/01/Java7%E4%B8%AD%E5%A2%9E%E5%8A%A0%E7%9A%84%E6%96%B0%E7%89%B9%E6%80%A7/

相關文章