20155315 2016-2017-2 《Java程序设计》第八周学习总结

教材学习内容总结

第14章 NIO与NIO2

1.认识NIO

NIO使用频道(Channel)来衔接数据节点,在处理数据时,NIO可以让你设定缓冲区(Buffer)容量,在缓冲区中对感兴趣的数据区块进行标记,像是标记读取位置、数据有效位置,对于这些区块标记,提供了clear()、rewind()、flip()、compact()等高级操作。

2.Channel: 衔接数据节点

  • Channel用于在字节缓冲区和位于通道另一侧的实体(通常是文件或者套接字)之间以便有效的进行数据传输。借助通道,可以用最小的总开销来访问操作系统本身的I/O服务。
  • Channel通道必须结合Buffer使用,不能直接向通道中读/写数据
  •   isOpen():确认Channel是否开启
    close:关闭通道。
  • FileChannel:从文件读写数据
  • SocketChannel:通过TCP读写网络数据
  • ServerSocketChannel: 可以监听新进来的TCP连接,并对每个链接创建对应的SocketChannel
  • DatagramChannel:通过UDP读写网络中的数据
  • read():
    • ReadableByteChannel定义的read()方法:将ReadableByteChannel中的数据读取至ByteBuffer
    • ScatteringByteChannel定义的read()方法:将ScatteringByteChannel分配到ByteBuffer数组中
  • write():
    • WritableByteChannel定义的write()方法:将ByteBuffer的数据写到WritableByteChannel
    • GatheringByteChannel定义的write()方法:将ByteBuffer的数据写到GatheringByteChannel

3.Buffer:块操作

Buffer 类是 java.nio 的构造基础。一个 Buffer 对象是固定数量的数据的容器,其作用是一个存储器,或者分段运输区,在这里,数据可被存储并在之后用于检索。缓冲区可以被写满或释放。对于每个非布尔原始数据类型都有一个缓冲区类,即 Buffer 的子类有:ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer 和 ShortBuffer没有 BooleanBuffer!!

  • buffer.clear() :

    clear() 函数将缓冲区重置为空状态。它并不改变缓冲区中的任何数据元素,而是仅仅将 limit 设为容量的值,并把 position 设回 0。
  • buffer.flip():

    从填充到释放状态的缓冲区翻转,在进行buffer读操作的时候,一般都会使用buffer.flip()函数。

    -**rewind() **函数与 flip() 相似,但不影响上界属性,它只是将位置值设回 0。
  • asRemaining() 会在释放缓冲区时告诉你是否已经达到缓冲区的上界
  • mark: 一个备忘位置。标记在设定前是未定义的(undefined)。使用场景是,假设缓冲区中有 10 个元素,position 目前的位置为 2(也就是如果get的话是第三个元素),现在只想发送 6 - 10 之间的缓冲数据,此时我们可以 buffer.mark(buffer.position()),即把当前的 position 记入 mark 中,然后 buffer.postion(6),此时发送给 channel 的数据就是 6 - 10 的数据。
  • buffer.reset() 重置位置

4.NIO2文件系统

  • FileSystems: 提供了许多方法来获得当前文件系统的相关信息。
  • Paths: 处理路径(文件和目录)
    • 创建path:Paths.get(String s)
    • 获得path的详细信息:getName(),getXX()…
    • 删除path的冗余信息:toRealPath
    • 转换path:toAbsolutePath()
    • 合并两个path:resolve()
    • 在两个path之间创建相对路径:relativeze()
    • 比较路径:equal(),startsWith(),endWith()
  • Files: 支持各种文件操作。

第15章 通用API

1.日志API

  • java.util.logging包提供了日志功能相关类与接口,不必额外配置日志组件,就可在标准Java平台使用是其好处。
  • 使用日志的起点是Logger类,Logger类的构造函数标示为protected,不是java.util.logging同包的类不能直接以new创建,要取得Logger实例,必修使用Logger的静态方法getLogger()。
  • 调用getLogger()时,必须指定Logger实例所属名称空间,名称空间以“.”作为层级区分,名称空间层级相同的Logger,其父Logger组态相同。

    通常在哪个类中取得的Logger,名称空间就会命名为哪个类全名。
  • 取得Logger实例后,可以使用Lever的静态成员指定信息层级。
  • Logger是记录信息的起点,要输出的信息,必须先通过Logger的Lever与Filter过滤,在通过Handler的Lever与Filter过滤,格式化信息的动作交给Formatter,输出信息的动作实际上是Handler负责。
  • Logger有层级关系,名称空间层级相同的Logger,父Logger组态会相同,每个Logger处理完自己的日志动作后,会向父Logger传播,让父Logger也可以处理日志。

2.指定日志层级

  • 1.Logger实例之父Logger组态,就是Logger.GLOBALLOGGERNAME名称空间Logger实例,可通过getLever()取得设定的Lever实例。
  • 2.Logger的信息处理会往父Logger传播,在没有做任何组态设定的情况下,默认取得的Logger实例,层级必须大于或等于Logger.GLOBALLOGGERNAME名称空间Logger实例设定的Lever.INFO,才有可能输出信息。
  • 3.通过setLever()设定Lever实例,若log()时指定的Lever实例内含的int值小于Logger设定的Lever实例内含的int值,Lever就不会记录信息。
  • 4.在经过Logger过滤之后,还得再经过Handler的过滤,一个Logger可以拥有多个Handler,可通过Logger的addHandler()新增Handler实例。实际上进行信息输出时,目前Logger的Handler处理完,还会传播给父Logger的所有Handler处理,可通过getHandlers()方法取得目前已有的Handler实例数组。
  • 5.在没有做任何组态设定的情况下,取得的Logger实例,只会使用Logger.GLOBALLOGGERNAME名词空间Logger实例拥有的Handler,默认是使用ConsoleHandler,为Handler的子类,作用是在控制台下输出日志信息,,默认地层级是Lever.INFO。

3.Handler

  • MemoryHandler不会格式化日志信息,信息会暂存于内存缓冲区,直至超过大小才将信息输出至指定的目标Handler。
  • StreamHandler可自行指定信息输出时使用的OutputStream实例,它与子类都会使用指定的Formatter格式化信息。
  • ConsoleHandler创建时,会自动指定OutputStream为System.err,所以日志信息会显示在控制台。
  • FileHandler创建时会建立日志输出时使用的FileOutputStream,文档位置与名称可以使用模式字符串指定。
  • SocketHandler创建时可以指定主机位置与端口,内部将自动建立网络联机,将日志信息传送至指定的主机。
  • Logger可以使用addHandler()新增Handler实例,使用removeHandler()移除Handler。
  • 在建立FileHandler指定模式字符串时,可以使用“%h”来表示用户的根目录,还可以使用“%t”取得系统暂存目录,或者使用“%g”自动为文档编号。

4.Handler、Formatter与Filter

  • Handler是负责输出,格式化交由Formatter,信息过滤是交由Filter。
  • 自定义Formatter,可以继承Formatter后操作抽象方法format(),这个方法会传入LogRecord,储存所有日志信息。

5. 国际化基础

  • 国际化:在不修改应用程序情况下,根据不同用户直接采用不同语言、日期格式等,这样的设计考虑称为国际化,简称i18n。
    • 国际化的三个标准是地区(Locale)信息、资源包(Resource bundle)与基础名称(Base name)。
  • 本地化:应用程序根据不同地区用户、呈现不同语言、日期格式。
  • 对于日后可能变动的文字信息,可以考虑将信息移至程序之外,使用ResourceBundle来做信息绑定。
    • ResourceBundle的静态getBundle()方法会取得一个ResourceBundle的实例,所给定的自变量名称是信息文档的主文件名,getBundle()会自动找到对应的.properties文档,取得ResourceBundle实例后,可以使用getString()指定键来取得。

6.正则表达式

规则表达式基本上包括两种字符:字面意义字符和元字符。

  • 字面意义字符是指按照字面意义比较的字符
    • 字母和数字在规则表达式中,都是按照字面意义比较,有些字符之前加上了\之后,会被当做元字符。
    • 元字符在规则表达式中有特殊意义,如! $ ^ ( ) + = { } [ ] | \ : ?等。如果不确定哪些标点符号字符要加上忽略字符,可以在每个标点符号前加上\。
    • 可使用split()方法依\切割。
  • 元字符时不按照字面比较,在不同情境有不同意义的字符。
    • 多个字符可以分归在一起,成为一个字符类。字符类会比较文字中是否有“任一个”字符符合字符类中某个字符。
    • 归类字符的方式之一是将字符放在[]中。
    • []中的字符时“或”的意思,|在字符类中只是个字面意义字符,不会被当做“或”来表示。连字符-作为字符类元字符,表示一段文字范围。字符类中可以使用作为字符类元字符,[]则作为反字符类。
  • 贪婪、逐步、独吐量词
    • 贪婪量词:尽可能找出长度最长的符合文字
    • 逐步量词(在贪婪量词后加?):尽可能找出长度最短的符合文字(懒惰量词、非贪婪量词)
    • 独吐量词(在贪婪量词后加+):比较器看到独吐量词是,会先将剩余文字吃掉,然后看看独吐量词部分是否符合吃下的文字。
  • 边界比较
    • 边界比较用来表示文字必须符合指定的边界条件,也就是定位点,因此这类表示式也常称为锚点。
  • 分组与参考
    • 可以使用()来将规则表达式分组,除了作为子规则表示式之外,还可以搭配量词使用。

      分组回头参考时,是在\后加上分组计数,表示参考第几个分组的比较结果。

7. Pattern与Matcher

  • 在取得Pattern实例后,可以使用的方法有:
    • split()方法:将指定字符串依规则表达式切割
    • matcher()方法:指定要比较的字符串
    • find()方法:看看是不是有下一个符合字符串
    • lookingAt():看看字符串开头是否符合规则表达式
    • group():可以返回符合的字符串。
  • 在取得Matcher实例后,可以使用的方法有 :
    • replaceAll()可以将符合规则表达式的部分以指定的字符串取代
    • replaceFirst()取代首个组合规则表达式的部分
    • replaceEnd()取代最后符合规则表达式的部分
    • start()方法可以取得符合字符串的初始索引
    • end()方法可以取得符合字符串最后一个字符后的索引
8.JDK8 API增强功能
  • StringJoiner、Arrays新增API
    • 1.String.join()、StringJoiner

      String新增join()静态方法可以指定每个字符串间以逗号分隔进行连接。
    • 2.Arrays

      Arrays上新增parallelPrefix()、parallelSetAll()与parallelSort()方法,parallelSort()方法,可以将指定的数组分为子数组并以平行化方式分别排序,然后再进行合并排序。指定的数组之元素必须操作`Comparable。
  • Stream相关API

    Files上有lines()、list()、walk()等方法。

    Stream、InStream、DoubleStream等都有of()静态方法,可以使用可变长度自变量方式指定元素。

教材学习中的问题和解决过程

  • 问题1:io和nio的区别?

  • 解决1:

    • 传统的socket IO中,需要为每个连接创建一个线程,当并发的连接数量非常巨大时,线程所占用的栈内存和CPU线程切换的开销将非常巨大。
    • 使用NIO,不再需要为每个线程创建单独的线程,可以用一个含有限数量线程的线程池,甚至一个线程来为任意数量的连接服务。
    • 由于线程数量小于连接数量,所以每个线程进行IO操作时就不能阻塞,如果阻塞的话,有些连接就得不到处理,NIO提供了这种非阻塞的能力。
    • 也就是说,传统的IO操作在用户没有其他动作的时候还一直在后台运行,但是NIO操作就可以在一项操作没有继续的时候退出运行过程,继续其他操作,提高工作效率。
  • 问题2:NIO中的Channel和IO中的流有什么区别?

  • 解决2:

    区别|Stream|Channel

    ---|---|---

    支持异步| 不支持|支持

    是否可双向传输数据 | 不能,只能单向|可以,既可以从通道读取数据,也可以向通道写入数据

    是否结合Buffer使用|不|必须结合Buffer使用

    性能|较低|较高

  • 问题3:怎么理解分组与反向引用

  • 解决3:

    • 分组就是为了实现多个字符绑定在一起而加括号把这一组字符限定为一个整体。
    • 反向引用用于重复搜索前面某个分组匹配的文本。

代码调试中的问题和解决过程

问题1:

  • 代码链接
  • 在根目录下运行该程序,出现如下提醒,找不到properties文件中的内容

    20155315 2016-2017-2 《Java程序设计》第八周学习总结
  • 进入java文件所在的文件夹编译并运行,结果如下

    20155315 2016-2017-2 《Java程序设计》第八周学习总结

问题2:

  • 将properties中的输入换成中文,运行出现乱码

    20155315 2016-2017-2 《Java程序设计》第八周学习总结
  • 根据之前敲的代码,知道是utf-8格式的问题,设置了filecoding和termencoding,但显示还是乱码,目前不是很清楚为什么,等之后再多看书希望能解决。

代码托管

  • 用statistics脚本查看代码行数

    20155315 2016-2017-2 《Java程序设计》第八周学习总结

  • 代码提交结果

    20155315 2016-2017-2 《Java程序设计》第八周学习总结

上周考试错题总结

  • 11.A ________________ diagram helps us visualize the contents of and relationships among the classes of a program(___有助于我们查看程序中类的内容和它们之间的关系).

A . class and object(类和对象)

B . UML(UML类图)

C . object-oriented(面向对象)

D . public

E . private

正确答案: B

理解情况:UML图帮助我们可视化程序的类之间的内容和关系。其他选择不涉及任何类型的图表。

  • 12.When applied to instance variables, the ________________ visibility modifier enforces encapsulation(当应用到实例变量时,____可见性修饰符强制执行封装).

A . static

B . final

C . public

D . private

E . none of the above(以上都不是)

正确答案: D

理解情况:private修饰符防止不适当的数据访问,因此促进封装。选择A和B不是可见性修饰符,而选择C是可见性修饰符,允许对对象数据的公共访问,这违背了封装的原则。

  • 14.__________________ parameters are the values that are used when calling a method(___参数是调用方法时传给方法的值).

A . formal(形式参数)

B . actual(实际参数)

C . useful(有用的参数)

D . informal(非正式参数)

E . none of the above(以上都不是)

正确答案: B

理解情况:调用方法时发送实际参数。定义方法时使用形式参数。

  • 16.An object can be thought of as a blueprint for a set of classes(对象被认为是类集合的蓝图).

A . true

B . false

正确答案: B

理解情况:类可以被看作是一组对象的蓝图,而不是另一种方式。

  • 17.When an object is passed to a method, the actual and formal parameters become aliases(当把对象传递给方法时,实参和形参互为别名).

A . true

B . false

正确答案: A

理解情况:实际参数是发送到方法中的数据。方法定义中使用了形式参数。当对象被发送到一个方法时,这些值都是引用,它们成为彼此的别名。

  • 20.Given the following, which answers can correctly fill in the blank? (Choose all that apply.)针对下面的代码,()中应填入哪个选项?

    LocalDate date = LocalDate.now();

    LocalTime time = LocalTime.now();

    LocalDateTime dateTime = LocalDateTime.now();

    ZoneId zoneId = ZoneId.systemDefault();

    ZonedDateTime zonedDateTime = ZonedDateTime.of(dateTime, zoneId);

    long epochSeconds = 0;

    Instant instant = ( );

A . Instant.now()

B . Instant.ofEpochSecond(epochSeconds)

C . date.toInstant()

D . dateTime.toInstant()

E . time.toInstant()

F . zonedDateTime.toInstant()

正确答案: F

理解情况:

选项A创建当前瞬间。

选项B正确转换秒到瞬间。

选项F也是一个适当的转换。

选项C,D和E是不正确,因为源对象不代表时间点。

没有时区,java不知道什么时候使用现在的时间。

  • 20.What is the output of the following code?(下面代码的运行结果是?)
    LocalDate date = LocalDate.of(2018, Month.APRIL, 30);
    date.plusDays(2);
    date.plusYears(3);
    System.out.println(date.getYear() + " "
    + date.getMonth() + " "+ date.getDayOfMonth());

A . 2018 APRIL 2

B . 2018 APRIL 30

C . 2018 MAY 2

D . 2021 APRIL 2

E . 2021 APRIL 30

F . 2021 MAY 2

G . A runtime exception is thrown.

正确答案: B

理解情况:日期开始为2018年4月30日。因为日期是不可变的,加上方法忽略返回值,结果不变。因此,选项B是正确的

  • 21.What is the output of the following code?(下面代码的运行结果是?)
     LocalDate date = LocalDate.of(2018, Month.APRIL, 40);
System.out.println(date.getYear() + " " + date.getMonth()
+ " "+ date.getDayOfMonth());

A . 2018 APRIL 4

B . 2018 APRIL 30

C . 2018 MAY 10

D . Another date

E . The code does not compile.

F . A runtime exception is thrown.

正确答案: F

理解情况:如果是无效的日期值传递,java就会抛出异常。没有第四十天的四月或任何其他月份,所以java抛出异常。

结对及互评

评分标准(满分10分)

  1. 从0分加到10分为止

  2. 正确使用Markdown语法(加1分):

    • 不使用Markdown不加分
    • 有语法错误的不加分(链接打不开,表格不对,列表不正确...)
    • 排版混乱的不加分
  3. 模板中的要素齐全(加1分)

    • 缺少“教材学习中的问题和解决过程”的不加分
    • 缺少“代码调试中的问题和解决过程”的不加分
    • 代码托管不能打开的不加分
    • 缺少“结对及互评”的不能打开的不加分
    • 缺少“上周考试错题总结”的不能加分
    • 缺少“进度条”的不能加分
    • 缺少“参考资料”的不能加分
  4. 教材学习中的问题和解决过程, 一个问题加1分

  5. 代码调试中的问题和解决过程, 一个问题加1分

  6. 本周有效代码超过300分行的(加2分)

  • 一周提交次数少于20次的不加分

6 其他加分:

  • 周五前发博客的加1分

    - 感想,体会不假大空的加1分

    - 排版精美的加一分

    - 进度条中记录学习时间与改进情况的加1分

    - 有动手写新代码的加1分

    - 课后选择题有验证的加1分

    - 代码Commit Message规范的加1分

    - 错题学习深入的加1分

    7 扣分:

    - 有抄袭的扣至0分

    - 代码作弊的扣至0分

点评模板:

  • 博客中值得学习的或问题:

    • xxx
    • xxx
    • ...
  • 代码中值得学习的或问题:

    • xxx
    • xxx
    • ...
  • 基于评分标准,我给本博客打分:XX分。得分情况如下:xxx

  • 参考示例

点评过的同学博客和代码

体会

这周代码主要是关于输入输出和通用API的代码,14章的代码主要用来访问目录,包括在Linux中常用的ls、dir等等命令,通过这一章的学习,我懂得了这些命令行在系统中是如何查找访问目录的,也更了解了系统的运行过程。

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时
第一周 20/20 1/1 10/10 安装了JDK、IDEA和Git,写了第一个Java程序
第二周 97/117 2/3 20/30 用Linux上传代码,熟悉修改文件的命令行
第三周 336/453 2/4 35/65 在Linux上安装JDK和IDEA,更熟悉vi的操作指令以及修改时需要注意的地方。
第四周 851/1304 1/5 25/90 学习用JDB调试程序
第五周 834/2138 1/7 32/122 能自己设计简单的程序,遇到问题也基本上能通过前面的学习和查资料解决,还有问题没有得到解决。
第六周 573/2711 1/8 15/137 理解课本中的内容并自己把之前的代码加以改正,更理解程序的作用,继续学习用JDB调试程序
第七周 400/3111 2/10 20/157 用IDEA编辑并调试程序,设置断点,完成了实验一
第八周 403/3511 2/10 20/177 熟悉通用API,深入学习代码并测试代码
  • 计划学习时间:25小时
  • 实际学习时间:20小时

参考资料

上一篇:9. nginx服务实验笔记


下一篇:电子标签拣货系统DPS