[读书笔记]《Java程序员修炼之道》

本文详细介绍了Java7新增的功能,包括switch支持String、数字常量的新形式、改进的异常处理等,并重点阐述了NIO的新特性,如Path类的使用、文件系统操作、文件修改通知等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请注明:本文来自:mrcode markdown博客:http://www.mrcode.cn/zhuqiang/article/details/22.html

Java7新特性

  1. switch支持String
  2. 数字常量的新形式:
    1. 二进制文本:如0x10000
    2. 使用下划线分割数字常量:如 int a = 22_222
  3. 改进的异常处理
    1. 在catch的时候可以使用 | 来链接不同的异常
      一般用于异常归类,比如 格式化数字出错,计算中出错,都能归类为计算错误?
    2. final 重抛
      java
      try{
      }catch(final Exception e){ throw e}

      说实话没有看懂这个重抛的意思
  4. try-with-resources(TWR)
    作用就是把资源放在try的圆括号中,那么就能自动帮你关闭资源文件,但是api本身自带的异常你还是需要catch的。

    语法:

        try(OutputStream out = new FileOutputStream("sss")){
            out.write(1);
        }catch(Exception e){}

    记住try()中只能放置资源文件的返回对象的操作语句,如果没有检测到有显示的资源对象,将会提示语法错误

  5. 钻石语法
    就是创建泛型的时候,右边的new Arraylist<>()中的泛型可以省略,原文提案“为泛型实例创建而做的类型推断改进”说名称太长,从而叫做钻石语法

  6. 变参警告位置的修改
    这个感觉没有说明白,就不记录了

NIO

path

描述
Path可以用来获取路径信息,访问该路径中的个元素,将路径转换为其他形式,或提取路径中的一部分。有的方法还可以匹配路径字符串以及移除路径中的冗余项
Paths工具类,提供返回一个路径的辅助方法,比如get(String first,String…more) 和get(URI uri)
FileSystem与文件系统交互的类,无论是默认的文件系统,还是通过其统一资源标识(URI)获取的可选文件系统
FileSystems工具类,提供各种方法,比如其中用于返回默认文件系统的FileSystems.getDefault()
        Path path = Paths.get("F:\\技术文档\\pdf");
        System.out.println(path.toAbsolutePath());
        System.out.println(path.toFile().exists());
        System.out.println(path.getNameCount());
        // TWR 自动关闭流
        try(
                //可以过滤到指定的文件
                DirectoryStream<Path> paths = Files.newDirectoryStream(path,"Java*");
            ){
            for (Path path1 : paths) {
                System.out.println(path1);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

遍历文件

    @Test
    public void fun_ml(){
        Path path = Paths.get("F:\\");
        try {
            //给定一个对象FileVisitor,能帮你遍历到 给定的path下的所有文件
            Path fileTree = Files.walkFileTree(path, new MyFileVisitor());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // SimpleFileVisitor 是java默认实现的一个类,可以通过扩展该类来实现对某个目录下的所有文件的操作
    private class MyFileVisitor extends SimpleFileVisitor<Path>{
        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
            System.out.println(file.getFileName());
            System.out.println(JSON.toJSONString(attrs));
            return super.visitFile(file, attrs);
        }
    }

nio 的文件系统

以下部分对于传统的io都进行了增强

描述
Files让你轻松复制、移动、删除或处理文件的工具类,有你所需要的所有方法
WatchService用来监视文件或目录的核心类,不管他们有没有变化

文件常用操作

一些特定系统上的权限等操作,在使用的时候再深入

    @Test
    public void fun_files() throws IOException {
        Path path = Paths.get("F:\\技术文档\\pdf\\demo");
        // 在linux 上面创建文件目录,加上权限
/*        Files.createDirectories(path,
                PosixFilePermissions.asFileAttribute(
                        PosixFilePermissions.fromString("rw-rw-rw")));*/
        Files.createDirectories(path); //对于目录,不存在的直接创建,存在的会创建失败,但是api已经将异常过滤掉了
        Path file = Paths.get(path.toString(), "text.txt");
//        Files.createFile(file); //如果已经存在该文件,将会抛出异常

        Path file2 = Paths.get(path.toString(), "text2.txt");
//        Files.copy(file, file2); //文件复制
        Path file3 = Paths.get(path.toString(), "text3.txt");
//        Files.move(file2,file3); //文件移动
        Files.delete(file3); //文件删除
    }

 @Test
    public void fun_file_attr() throws IOException {
        Path path = Paths.get("F:\\技术文档\\pdf\\demo");
        System.out.println(Files.getLastModifiedTime(path)); //获取最后一次修改时间
        System.out.println(Files.readAttributes(path,"*")); //读取所有的属性
    }

快速读写数据

对文件的读写操作

    @Test
    public void fun_file_read(){
        Path path = Paths.get("F:\\技术文档\\pdf\\demo\\text.txt");
        if(!path.toFile().exists()){
            System.out.println("文件不存在");
        }

        try(
                //文件编码一定要正确,否则将读取异常
                BufferedReader bufferedReader = Files.newBufferedReader(path, StandardCharsets.UTF_8);
            ){
            String line = null;
            while ((line = bufferedReader.readLine()) != null){
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void fun_file_write(){
        Path path = Paths.get("F:\\技术文档\\pdf\\demo\\text.txt");
        try(
              //默认是没有文件则创建一个新文件,有文件则直接覆盖
//            BufferedWriter bufferedWriter = Files.newBufferedWriter(path, StandardCharsets.UTF_8);
            //该模式是没有文件则报错。
//            BufferedWriter bufferedWriter = Files.newBufferedWriter(path, StandardCharsets.UTF_8,StandardOpenOption.APPEND);
              //通过打开模式可以快速的帮我们进行一些逻辑的设定,比如下面的组合,文件不存在则先创建
            BufferedWriter bufferedWriter = Files.newBufferedWriter(path, StandardCharsets.UTF_8,
                    StandardOpenOption.APPEND,
                    StandardOpenOption.CREATE);
        ){
            bufferedWriter.write("追加文件");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

使用新的简化读取方式

上面的那种还是基于java6的读取思路,这里又进行了进一步的封装,我想是针对于小文件进行快速的读取

    @Test
    public void fun_file_simpl_read() throws IOException {
        // 简化读取
        Path path = Paths.get("F:\\技术文档\\pdf\\demo\\text.txt");
        List<String> strings = Files.readAllLines(path, StandardCharsets.UTF_8);
        System.out.println(Arrays.toString(strings.toArray()));
    }

文件修改通知

对于平时项目的使用来说,一般在于什么时候/时机读取文件?比如说读取一个配置文件,需要修改之后就立即加载生效类似的。就要用到文件修改通知了。

    @Test
    public void fun_watchservice() {
        try (
                WatchService watchService = FileSystems.getDefault().newWatchService();
        ) {
            Path path = Paths.get("E:\\学习\\"); //只能对一个目录下的文件进行监控,有点类似zookpooer的节奏
            // 在该路径上注册
            WatchKey watchKey = path.register(watchService,StandardWatchEventKinds.ENTRY_MODIFY,StandardWatchEventKinds.ENTRY_DELETE); //对修改进行监控
            boolean flag = true; //用于跳出循环
            while(flag){
                WatchKey take = watchService.take(); //如果有事

                // 件触发,将会被放入服务队列中,等待处理
//                List<WatchEvent<?>> watchEvents = watchKey.pollEvents(); //获取该key上的所有事件:其实没有太明白 这个WatchService 和 WatchKey的关系。所以下面的代码有点没有搞明白
                List<WatchEvent<?>> watchEvents = take.pollEvents();
                for (WatchEvent<?> watchEvent : watchEvents) {
                    if(watchEvent.kind() == StandardWatchEventKinds.ENTRY_MODIFY){
                        Object context = watchEvent.context(); //在windows中 该对象类型原型是私有的 WindowsPath类型,但是该类的实现接口也是path
                        Path file = (Path)context; //返回的是针对该目录的一个相对路径
                        Path child = path.resolve(file); // 不太看得懂英文说明:这里需要转换为绝对路径,这个是一个简便的转换
                        List<String> strings = Files.readAllLines(child, StandardCharsets.UTF_8);
                        System.out.println(Arrays.toString(strings.toArray()));
                    }
                }
                watchKey.reset(); //重置监控key
            }

        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

对上面代码的第一遍理解:
1. 只能对目录下的文件或则目录的一些变化监控
2. 没有搞明白这个服务的提供大体原理,所以对于api来说不太会用

SeekableByteChannel

FileChannel 是该接口
java.nio.channels
public interface SeekableByteChannel 的实现,
功能就是:在文件读取或写入时保持当前位置,比如说,下面的代码就是读取了文件最后的三个字节。

    public void fun_channel(){
        Path path = Paths.get("F:\\技术文档\\pdf\\demo\\text.txt");
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        try (
                FileChannel fc = FileChannel.open(path, StandardOpenOption.READ);
                ){
            // fc.size 返回的是自己数,utf中一个汉字占三个字节
            int read = fc.read(buffer, fc.size() - 3); // 读取该文件最后的三个字节
            System.out.println(new String(buffer.array()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

异步i/o操作

.

.

.

太难了。 等待用到的时候再学习

.

.

.

.

.

.

.

.

.


关键技术

  1. 控制反转(IoC)和依赖注入(Di)
  2. 涨或依赖注入技术为什么如此重要
  3. JSR-330如何统一了Java中的Di
  4. 常见的JSR-330注解,比如@Inject
  5. Guice3简介,JSR-330的参考实现(RI)

依赖注入

  1. 控制反转(IoC)
    好莱坞原则-“不要给我打电话,我们会打给你”
    其实就算是游戏命令行控制行为,还是改编为 界面控制行为,感觉都没能好好的理解这个控制反转的说明,有一种朦胧的理解,就是由你主动的操作,变成了由我主动操作。

  2. 依赖注入
    依赖注入是IoC的一种特定形态,是指寻找依赖项的过程不在当前执行代码的直接控制之下。一般由第三方框架帮你处理。
    可以把IocRon容器看作运行时环境。Java中为依赖注入提供的容器有Guice、Spring和PicoContainer

注: 显式的创建一个对象,并把该对象注入到另外一个服务中去; 这个过程也算是注入。 不过把这个过程交给了第三方框架去做,也就是Ioc容器和Di依赖注入

Di的好处

好处描述例子
松耦合代码不再紧紧的绑定到依赖项的创建上。如果能与面向接口编程的技术相结合,意味着你的代码再也不用紧紧的绑定到依赖项的具体实现上了
易测性作为松耦合的延伸,还有个特殊的用列值得一提。为了测试,可以把测试替身(后面章节会记录)作为依赖项注入到对象中
更强的内聚性你的代码可以专注于执行自己的任务,不用为了载入和配置依赖而分心。这样还能增强代码的可读性你的dao对象可以专注于查询工作,不用考虑JDBC驱动的细节
可重用组件作为松耦合的延伸,你的代码应用范围会更加宽广,那些可以提供自己特定实现的用户都可以使用你的代码
更轻盈的代码你的代码不再需要跨层传递依赖项,而是可以在需要依赖项的地方直接注入你不再需要把jdbc驱动的细节信息从service类往下传递,而是在真正需要它的dao中直接注入这个驱动实例

Java中标准化DI

从Jee6开始构建了自己的依赖注入体系(CDI),由JSR-299规范确定。JSR-299构建在JSR-330基础之上。javax.inject jdk5.6.7都支持该标准。

javax.inject 包:
指明了获取对象的一种方式,与传统的构造方法、工厂模式和服务定位器模式(比如JNDI)等相比,这种方式的可重用性、可测试线和可维护性都得到了极大提升。这种方式称为依赖注入,对于大多数非小型应用程序都很有帮助。

一个接口:Provider接口
5个注解类型:@Inject、@Qualifier、@Named、@Scope、@Singleton

这一章的讲解貌似都没有什么干货,直接忽略


这本书结束: 除了让我对于nio有了一个基础的了解之外,其他的章节可以说是没有什么亮点的。 至少让我感觉是这样的。
这本书总的来说,不推荐看,讲的东西都太浅了,有的直接扒拉概念,看完这本书,唯一的感觉就是知道了点nio的基础知识

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值