jdk7新特性

来源:互联网 发布:平板怎么下载软件 编辑:程序博客网 时间:2024/05/19 20:01

前几天在微信订阅号"java技术"看了一下关于jdk7新特性方面的介绍,在这里总结分享一下.

1.自动资源管理(TWR)--try with resource

Java中某些资源是需要手动关闭的,如InputStream,Writes,Sockets等。这个新的语言特性允许try语句本身申请更多的资源,这些资源作用于try代码块,并自动关闭。

package yang.zhiran.TWR;import java.io.BufferedReader;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.IOException;public class test {public static void main(String[] args) {/* * Java中某些资源是需要手动关闭的,如InputStream,Writes,Sockets,Sql classes等。 * TWR特性允许try语句本身申请更多的资源,这些资源作用于try代码块,并自动关闭。 */String path="C:\\test.txt";try {String contentOld=oldMethod(path);System.out.println("old:"+contentOld);String contentNew=newMethod(path);System.out.println("new:"+contentNew);} catch (IOException e) {e.printStackTrace();}}public static String oldMethod(String path) throws IOException{BufferedReader br=null;try {br = new BufferedReader(new FileReader(path));return br.readLine();} catch (Exception e) {e.printStackTrace();return "";}finally{br.close();}}public static String newMethod(String path){BufferedReader br=null;try {br = new BufferedReader(new FileReader(path));return br.readLine();} catch (Exception e) {e.printStackTrace();return "";}}}


2.diamond语法,自动推断类型:

package yang.zhiran.diamond;import java.util.ArrayList;import java.util.HashMap;import java.util.Map;import java.util.List;public class test {public static void main(String[] args) {/* * 类型推断:diamond语法   */Map<String,List<String>> map=new HashMap<>();List<String> list=new ArrayList<>();list.add("xxx");list.add("yyy");map.put("yzr", list);System.out.println(map);}}


3.数字字面量下划线支持

package yang.zhiran.intvar;public class test {/** * @param args */public static void main(String[] args) {//在Java 7中可以使用下划线分隔长int以及longint number=100_00_0;//等价于100000System.out.println(number);}}


4..switch中使用string

1.7之前switch只支持int和enum两种类型,现在也可以支持string

package yang.zhiran.switch7;public class test {/** * @param args */public static void main(String[] args) {switch ("YZR") {case "YZR":System.err.println("YZR");break;default:System.err.println("default");break;}}}


5.改善后的异常处理

在Java7之前的异常处理语法中,一个catch子句只能捕获一类异常。在要处理的异常种类很多时这种限制会很麻烦。每一种异常都需要添加一个catch子句,而且这些catch子句中的处理逻辑可能都是相同的,从而会造成代码重复。虽然可以在catch子句中通过这些异常的基类来捕获所有的异常,比如使用Exception作为捕获的类型,但是这要求对这些不同的异常所做的处理是相同的。另外也可能捕获到某些不应该被捕获的非受检查异常。而在某些情况下,代码重复是不可避免的。比如某个方法可能抛出4种不同的异常,其中有2种异常使用相同的处理方式,另外2种异常的处理方式也相同,但是不同于前面的2种异常。这势必会在catch子句中包含重复的代码。

对于这种情况,Java7改进了catch子句的语法,允许在其中指定多种异常,每个异常类型之间使用“|”来分隔。如例:

package yang.zhiran.catch7;public class test {/** * @param args */public static void main(String[] args) {Object obj=null;try{if(obj.toString().equals("") && 19/0 >0){}}catch (NullPointerException | ArithmeticException e) {System.out.println("捕获 除数为0 和 空指针 异常");//e.printStackTrace();}}}

6.Path

在新的文件I/O中,Path是必须掌握的关键类之一,用Path对象来实现对文件或者文件夹的操作。Path通常代表文件系统中的位置,比如C:\workspace\java7developer(Windows文件系统中的目录)或/usr/bin/zip(*nix文件系统中zip程序的位置)。

注意:Path是一个抽象构造,你所创建和处理的Path可以不马上绑定到对应的物理位置上。

java.nio.file.Paths 包含了用于创建Path对象的静态方法
java.nio.file.Path 包含了大量用于操纵文件路径的方法
java.nio.file.FileSystems 用于访问文件系统的类
java.nio.file.FileSystem 代表了一种文件系统,例如Unix下的根目录为 / ,而Windows下则为C盘

一旦获得某个路径对应的Path对象,我们就能方便的获取文件系统中的各种信息,已及操作该path。

Path path = FileSystems.getDefault().getPath("C:\\test\\test.txt");    System.out.printf("文件名称: %s\n", path.getFileName());    System.out.printf("根目录: %s\n", path.getRoot());    for (int index = 0; index < path.getNameCount(); index++) {        System.out.printf("getName(%d): %s\n", index, path.getName(index));    }    System.out.printf("路径截取: %s\n", path.subpath(0, 2));    System.out.printf("路径截取: %s\n", path.subpath(0, 1));    System.out.printf("父目录: %s\n", path.getParent());    System.out.println("是否绝对路径:"+path.isAbsolute());    path = Paths.get("F", "test.txt");    System.out.printf("绝对路径地址: %s\n", path.toAbsolutePath());    System.out.println("是否绝对路径:"+path.isAbsolute());        //获取文件信息    path = Paths.get("C:\\test\\test.txt");    BasicFileAttributes attributes = Files.readAttributes(path, BasicFileAttributes.class);    System.out.println("Creation Time: " + attributes.creationTime());    System.out.println("Last Accessed Time: " + attributes.lastAccessTime());    System.out.println("Last Modified Time: " + attributes.lastModifiedTime());    System.out.println("File Key: " + attributes.fileKey());    System.out.println("isDirectory: " + attributes.isDirectory());    System.out.println("Other Type of File: " + attributes.isOther());    System.out.println("Regular File: " + attributes.isRegularFile());    System.out.println("Symbolic File: " + attributes.isSymbolicLink());    System.out.println("Size: " + attributes.size());
操作文件

通用,Java7也提供了简单的api可以让我们非常简单的复制、移动和删除文件以及路径。

            //操作文件    Path directoryPath = Paths.get("C:/home");    //创建目录    Files.createDirectory(directoryPath);//不能存在多个为存在的文件夹,只能只有一个    System.out.println("Directory created successfully!");    Path filePath = Paths.get("C:/home/test.txt");    //创建文件    Files.createFile(filePath);    System.out.println("File created successfully!");        Path newFile = Paths.get("C:/home/newFile.txt");        Files.createFile(newFile);    System.out.println("File created successfully!");    Path copiedFile = Paths.get("C:/home/copiedFile.txt");    Files.copy(newFile, copiedFile, StandardCopyOption.REPLACE_EXISTING);    System.out.println("File copied successfully!");    Files.createDirectory(Paths.get("C:/home/projects"));    Path sourceFile = Paths.get("C:/home/projects/note_bak1.txt");    boolean result = Files.deleteIfExists(sourceFile);    if (result) {        System.out.println("File deleted successfully!");    }    else{    Files.createFile(sourceFile);    }    sourceFile = Paths.get("C:/home/projects/note_bak1.txt");    Files.delete(sourceFile);    System.out.println("File deleted successfully!");

在调用createFile方法时,如果想要创建的文件已经存在,FileAlreadyExistsException会被抛出。createFile和createDirectory这个两个方法都是原子性的,即要不整个操作都能成功或者整个操作都失败。复制一个文件同样非常简单,Files的copy方法就可以实现。在复制文件时,我们可以对复制操作加一个参数来指明具体如何进行复制。java.lang.enum.StandardCopyOption这个枚举可以用作参数传递给copy方法。ATOMIC_MOVE原子性的复制COPY_ATTRIBUTES将源文件的文件属性信息复制到目标文件中REPLACE_EXISTING替换已存在的文件删除文件可以使用Files的delete和deleteIfExists这两个方法。顾名思义,当文件不存在时deleteIfExists的删除结果为false。

目录遍历
                //目录遍历//得到该path下所有.txt文件的目录流接口Path dir= Paths.get("C:\\");        DirectoryStream<Path> txtStream=Files.newDirectoryStream(dir,"*.txt");        System.out.println("===txt===");        for(Path item : txtStream){            System.out.println(item.toAbsolutePath()+":"+item.getFileName());        }

进行目录及目录树遍历(监听遍历)

package yang.zhiran.path;import java.io.IOException;import java.nio.file.FileVisitResult;import java.nio.file.Path;import java.nio.file.SimpleFileVisitor;import java.nio.file.attribute.BasicFileAttributes;public class VisitorFile extends SimpleFileVisitor<Path>{    //访问目录及子目录中的每个path的方法    @Override    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {        System.out.println(file.toAbsolutePath()+":"+file.getFileName());        //表示继续遍历        return FileVisitResult.CONTINUE;    }    //访问某个path失败时调用的方法,默认抛出异常    @Override    public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {        System.out.println(file+";"+exc.getClass());        //表示继续遍历        return FileVisitResult.CONTINUE;    }}

                //进行目录及目录树遍历,打印出所有遍历到的文件        System.out.println("===dir tree===");        Files.walkFileTree(dir,new VisitorFile());

7.快速读写

Java 7可以直接用带缓冲区的读取器和写入器或输入输出流(为了和以前的Java I/O代码兼容)打开文件。

package yang.zhiran.newBuffered;import java.io.BufferedWriter;import java.io.IOException;import java.nio.charset.Charset;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.Paths;import java.util.List;public class test {/* * 文件读写 */public static void main(String[] args) throws IOException {/*Path path= Paths.get("C:/test.txt");BufferedWriter writer = Files.newBufferedWriter(path,Charset.forName("utf-8"));//StandardOpenOption.APPENDwriter.write("hello,java7");                writer.newLine();                writer.write("test");                System.out.println("ok");                writer.close();                List<String> lines= Files.readAllLines(path,Charset.forName("utf-8"));                System.out.println(lines);                */                        Path path = Paths.get("C:/test.txt");try ( // 如果文件存在则直接打开,否则创建文件BufferedWriter writer = Files.newBufferedWriter(path,Charset.forName("utf-8"));// 可以指定打开文件的模式,这里表示追加文件// BufferedWriter writer=Files.newBufferedWriter(path,// Charset.forName("utf-8"), StandardOpenOption.APPEND);) {writer.write("hello,java7");writer.newLine();writer.write("test");System.out.println("ok");}List<String> lines = Files.readAllLines(path, Charset.forName("utf-8"));System.out.println(lines);}}

8.监听文件

要实现监听文件的变更然后马上做出响应,在Java7之前,除了不断的循环似乎没什么好办法,而且实现也很麻烦。Java7推出了一个WatchService来解决这个问题。

package yang.zhiran.watchService;import java.io.IOException;import java.nio.file.FileSystems;import java.nio.file.Path;import java.nio.file.Paths;import java.nio.file.StandardWatchEventKinds;import java.nio.file.WatchEvent;import java.nio.file.WatchKey;import java.nio.file.WatchService;public class test {/** * @param args */public static void main(String[] args) {final Path path = Paths.get("C:\\home");System.out.println("begin");        try (WatchService watchService = FileSystems.getDefault().newWatchService()) {            //给path路径加上文件观察服务            path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,                    StandardWatchEventKinds.ENTRY_MODIFY,                    StandardWatchEventKinds.ENTRY_DELETE);            // start an infinite loop            while (true) {                final WatchKey key = watchService.take();                for (WatchEvent<?> watchEvent : key.pollEvents()) {                    final WatchEvent.Kind<?> kind = watchEvent.kind();                    if (kind == StandardWatchEventKinds.OVERFLOW) {                        continue;                    }                    //创建事件                    if (kind == StandardWatchEventKinds.ENTRY_CREATE) {                    System.out.println("create");                    }                    //修改事件                    if (kind == StandardWatchEventKinds.ENTRY_MODIFY) {                    System.out.println("modify");                    }                    //删除事件                    if (kind == StandardWatchEventKinds.ENTRY_DELETE) {                    System.out.println("delete");                    }                    // get the filename for the event                    final WatchEvent<Path> watchEventPath = (WatchEvent<Path>) watchEvent;                    final Path filename = watchEventPath.context();                    // print it out                    System.out.println(kind + " -> " + filename);                }                // reset the keyf                boolean valid = key.reset();                // exit loop if the key is not valid (if the directory was                // deleted, for                if (!valid) {                    break;                }            }        } catch (IOException | InterruptedException ex) {            System.err.println(ex);        }}}

9 指定position读写文件

打开文件,定位到指定的位置,然后读或写文件内容。

在Javs7中,SeekableByteChannel接口提供了这个功能。

package yang.zhiran.fileChannel;import java.io.IOException;import java.nio.ByteBuffer;import java.nio.channels.Channels;import java.nio.channels.FileChannel;import java.nio.file.Paths;import java.nio.file.StandardOpenOption;public class test {/** * 定位position读写文件内容 * @param args * @throws IOException  */public static void main(String[] args) throws IOException {FileChannel fileChannel=FileChannel.open(Paths.get("C:\\test.txt"), StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE);        fileChannel.write(ByteBuffer.wrap("hello,java".getBytes()));        fileChannel.position(0);//定位到文件开头        //fileChannel.write(ByteBuffer.wrap("seek".getBytes()));//替换        //fileChannel.write(ByteBuffer.wrap("seek".getBytes()),1);        fileChannel.write(ByteBuffer.wrap("seek".getBytes(),3,1));        //fileChannel.position(fileChannel.size());//定位到文件末尾        //fileChannel.write(ByteBuffer.wrap("end".getBytes()));        //将通道中的指定位置开始的内容传输到另一个通道中,这里传输到控制台       fileChannel.transferTo(0,fileChannel.size(), Channels.newChannel(System.out));}}

10.异步IO

Java7直接提供了用于异步操作io的各种通道。

新的异步功能的关键点,它们是Channel类的一些子集。包括:

AsynchronousFileChannel:针对文件;
AsynchronousSocketChannel :针对客户端的socket;
AsynchronousServerSocketChannel:针对服务器端的异步socket,用来接收到来的连接。
一些需要访问较大,耗时的操作,或是其它的类似实例,可以考虑应用此功能。

package yang.zhiran.asynchronous;import java.io.IOException;import java.nio.ByteBuffer;import java.nio.channels.AsynchronousFileChannel;import java.nio.charset.Charset;import java.nio.file.Path;import java.nio.file.Paths;import java.util.concurrent.Future;public class test {/** * @param args * @throws IOException  */public static void main(String[] args) throws IOException {//定义要打开的文件对应的path        Path path= Paths.get("C:\\test.txt");        //打开一个可以异步读写文件的通道        AsynchronousFileChannel channel=AsynchronousFileChannel.open(path);        //通道是基于ByteBuff读写的,所以需要声明一个bytebuff来存储要读写的数据        ByteBuffer bf=ByteBuffer.allocate(1024);//声明1024个字节的buff        //从0(文件开头)异步读取文件内容到bf,由于是异步操作,不管文件有没有读取完成,这句代码执行后立刻就会执行后面的代码,通过future可以知道结果        Future future=channel.read(bf,0);        System.out.println("文件读取中...");        //如果文件没有读完,可以继续干些别的事情        while(!future.isDone()){            System.out.println("我干别的了,你慢慢读");        }        System.out.println("文件读取完成");        bf.flip();        //打印bytebuff中的内容        System.out.println(Charset.forName("utf-8").decode(bf));        channel.close();}}

11.Fork/Join框架

Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架,使得应用能充分利用线程进行并行计算,并减少了线程间的竞争。

所谓Fork就是把一个大任务切分为若干子任务并行的执行,Join则是合并这些子任务的执行结果,最后得到这个大任务的结果。

比如计算1+2+。。+1000,可以分割成10个子任务,每个子任务分别对100个数进行求和,最终汇总这10个子任务的结果。

package yang.zhiran.forkJoin;import java.util.concurrent.ForkJoinPool;import java.util.concurrent.RecursiveTask;public class test extends RecursiveTask<Integer>{final int step=100;//表示每个任务最多只计算100个数字的和,比如从1加到200就分层1+100和101+200两个任务    private int from;//从哪里开始计算    private int to;//到哪里结束计算    public test(int from,int to){        this.from=from;        this.to=to;    }    //重写此方法,用于计算任务结果        @Override    protected Integer compute() {        if((to-from)<step){            //小于100个数,直接计算            return sum(from,to);        }        //拆分任务,一分为二        int middle=(from+to)/2;        test task1=new test(from,middle);        test task2=new test(middle+1,to);        //执行子任务(异步)        task1.fork();        task2.fork();        //等待子任务结果        int t1=task1.join();        int t2=task2.join();        return t1+t2;    }    private int sum(int from,int to){        System.out.println("from:"+from+",to:"+to);        int sum=0;        for(int i=from;i<=to;i++){            sum+=i;        }        return sum;    }    public static void main(String[] arg) throws Exception {        //fork/join需要ForkJoinPoll执行        ForkJoinPool pool=new ForkJoinPool();        System.out.println(pool.submit(new test(1,300)).get());    }}

Fork/Join使用两个类来完成以上两件事情:

ForkJoinTask

我们要使用ForkJoin框架,必须首先创建一个ForkJoin任务。它提供在任务中执行fork()和join()操作的机制。

通常情况下我们不需要直接继承ForkJoinTask类,而只需要继承它的子类,Fork/Join框架提供了以下两个子类:

RecursiveAction:用于没有返回结果的任务。
RecursiveTask :用于有返回结果的任务。
ForkJoinPool

ForkJoinTask需要通过ForkJoinPool来执行,它是一个特殊的ExecutorService.任务分割出的子任务会添加到当前工作线程所维护的双端队列中,进入队列的头部。当一个工作线程的队列里暂时没有任务时,它会随机从其他工作线程的队列的尾部获取一个任务。

12.反射新API

package yang.zhiran.methodHandle;import java.lang.invoke.MethodHandle;import java.lang.invoke.MethodHandles;import java.lang.invoke.MethodType;public class MethodHandlerTest {public static void main(String[] arg) throws Throwable{        //获取方法f1的methodType对象,表示此方法的返回值类型和参数类型        MethodType f1=MethodType.methodType(String.class,int.class);        MethodType f2=MethodType.methodType(void.class);//无参数,返回值是void的方法        MethodType f3=MethodType.methodType(void.class);        //通过MethodHandles.lookup()可以在一个类上根据方法名称和方法的methodType获取方法句柄        //查找普通方法        MethodHandle mf1=MethodHandles.lookup().findVirtual(MethodHandlerTest.class,"f1",f1);        MethodHandle mf2=MethodHandles.lookup().findVirtual(MethodHandlerTest.class,"f2",f2);        //查找静态方法        MethodHandle mf3=MethodHandles.lookup().findStatic(MethodHandlerTest.class,"f3",f3);        //通过方法句柄调用方法        MethodHandlerTest methodHandler=new MethodHandlerTest();        mf1.invoke(methodHandler,123);        mf2.invoke(methodHandler);        //使用invokeExact调用时,参数类型和返回值类型必须与方法签名的一致        String v=(String)mf1.invokeExact(methodHandler,1234);        //调用静态方法        mf3.invoke();    }    public String f1(int a){        System.out.println("f1"+a);        return a+"";    }    public void f2(){        System.out.println("f2");    }    public static void f3(){        System.out.println("f3");    }}