jdk7新特性

前几天在微信订阅号"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以及long
		int number=100_00_0;//等价于100000
		System.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.APPEND
		writer.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");
    }

}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值