20145330第八周《Java学习笔记》

时间:2023-02-25 14:32:09

20145330第八周《Java学习笔记》

第十五章 通用API

通用API

  • 日志:日志对信息安全意义重大,审计、取证、入侵检验等都会用到日志信息
  • 日志API
    • Logger:注意无法使用构造方法生成Logger对象
      • Logger logger=Logger.getLogger("xxx");
      • getLevel
      • setLevel
      • 调用getLogger()时,必须指定Logger实例所属名称空间(Name Space),名称空间以"."作为层级区分,名称空间层级相同的Logger,其父Logger组态相同。
      • 通常在哪个类中取得的Logger,名称空间就会命名为哪个类全名,也会以以下方式取得Logger:
      • Logger logger=Logger.getLogger(Main.class.getName());
      • 取得logger实例之后,可以使用log()方法输出信息,输出信息时可以使用Level的静态成员指定信息层级,例如:

import java.util.logging.*;

public class LoggerDemo {

public static void main(String[] args) {
Logger logger = Logger.getLogger(LoggerDemo.class.getName());
logger.log(Level.WARNING, "WARNING 訊息");
logger.log(Level.INFO, "INFO 訊息");
logger.log(Level.CONFIG, "CONFIG 訊息");
logger.log(Level.FINE, "FINE 訊息");
}
}

20145330第八周《Java学习笔记》

  • logger是记录信息的起点,要输出的信息,必须先通过logger的Level与Filter过滤,再通过Handler的Level与Filter过滤,格式化信息的动作交给Formatter,输出信息的动作实际上是Handler负责
    • Level
    • Handler:输出介质
  • 指定日志层级
    • 在经过logger过滤后,还得经过Handler的过滤
    • 若要显示INFO以下的信息,不仅要将logger的层及设定为Level.INFO,也得将Handler的层及设定为Level.INFO,例如:

import java.util.logging.*;

public class LoggerDemo2 {

public static void main(String[] args) {
Logger logger = Logger.getLogger(LoggerDemo2.class.getName());
logger.setLevel(Level.FINE);
for(Handler handler : logger.getParent().getHandlers()) {
handler.setLevel(Level.FINE);
}
logger.log(Level.WARNING, "WARNING 讯息");
logger.log(Level.INFO, "INFO 讯息");
logger.log(Level.CONFIG, "CONFIG 讯息");
logger.log(Level.FINE, "FINE 讯息");
}
}

20145330第八周《Java学习笔记》

  • 使用Handler与Formatter
    • logger可以使用addHandler()新增Handler实例,使用removeHandler()移除Handler,下面范例将logger与新建的FileHandler层及设定,并使用addHandler()设定logger实例:

import java.io.IOException;
import java.util.logging.*;

public class HandlerDemo {

public static void main(String[] args) throws IOException {
Logger logger = Logger.getLogger(HandlerDemo.class.getName());
logger.setLevel(Level.CONFIG);
FileHandler handler = new FileHandler("%h/config.log");
handler.setLevel(Level.CONFIG);
logger.addHandler(handler);
logger.config("Logger 组态完成");
}
}
  • 自定义Handler、Formatter、Filter
    • 如果java.util.logging包中提供的Handler成果都不符合需求,可以继承Handler类,操作抽象方法publish()、flush()与close()方法来自定义Handler
    • 操作时要记得,在职责分配上,Handler是负责输出,格式化是交由Formatter,而信息过滤是交由Filter

import java.time.Instant;
import java.util.logging.*;

public class FormatterDemo {

public static void main(String[] args) {
Logger logger = Logger.getLogger(FormatterDemo.class.getName());
logger.setLevel(Level.CONFIG);
ConsoleHandler handler = new ConsoleHandler();
handler.setLevel(Level.CONFIG);
handler.setFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
return "日志来自 " + record.getSourceClassName() + "."
+ record.getSourceMethodName() + "\n"
+ "\t层级\t: " + record.getLevel() + "\n"
+ "\t信息\t: " + record.getMessage() + "\n"
+ "\t时间\t: " + Instant.ofEpochMilli(record.getMillis())
+ "\n";
}
});
logger.addHandler(handler);
logger.config("自订 Formatter 信息");
}
}

20145330第八周《Java学习笔记》

  • 使用logging.properties
    • 实际上,可以通过logging.properties来设定logging组态,这样就很方便。

      国际化基础

  • 使用ResourceBundle
    • 对于日后可能变动的文字信息,可以考虑将信息移至程序外,方法是使用ResourceBundle来做信息绑定

import static java.lang.System.out;
import java.util.ResourceBundle;

public class Hello {

public static void main(String[] args) {
ResourceBundle res = ResourceBundle.getBundle("messages");
out.print(res.getString("cc.openhome.welcome") + "!");
out.println(res.getString("cc.openhome.name") + "!");
}
}
  • 使用Locale
    • 国际化的三个重要概念是地区信息(Locale)、资源包与基础名称
    • 地区信息代表了特定的地理、政治或文化区,地区信息可由一个语言编码与可选的地区编码来指定。
    • 地区信息的对应类是Locale,在建立Locale实例时,可以指定语言编码与地区编码

规则表示式

  • 规则表示式简介
    • 如果你有个字符串,项根据某个字符或字符串切割,可以使用string与split()方法。例如:

import static java.lang.System.out;

public class SplitDemo {

public static void main(String[] args) {

for(String token : "Justin,Monica,Irene".split(",")) {
out.println(token);
}

for(String token : "JustinOrzMonicaOrzIrene".split("Orz")) {
out.println(token);
}

for(String token : "Justin\tMonica\tIrene".split("\\t")) {
out.println(token);
}
}
}
  • 执行结果会分别针对逗号、Orz、Tab字符对字符串进行切割:

20145330第八周《Java学习笔记》

  • 字面意义字符
  • 字符类
  • 贪婪、逐步、独吐量词
  • 边界比较
  • 分组与参考

  • Pattern与Matcher
    • 在程序中使用规则表示式,必须先针对规则表示式做剖析,验证等动作,确定规则表式语法无错误,对字符串进行比较。
    • 使用group()方法可以返回符合的字符串,例如:

import static java.lang.System.out;
import java.util.regex.*;

public class PatternMatcherDemo {

public static void main(String[] args) {
String[] regexs = {".*foo", ".*?foo", ".*+foo"};
for(String regex : regexs) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher("xfooxxxxxxfoo");
out.printf("%s find ", pattern.pattern());
while(matcher.find()) {
out.printf(" \"%s\"", matcher.group());
}
out.println(" in \"xfooxxxxxxfoo\".");
}
}
}

20145330第八周《Java学习笔记》


import static java.lang.System.out;
import java.util.*;
import java.util.regex.*;

public class Regex {

public static void main(String[] args) {
Scanner console = new Scanner(System.in);
try {
out.print("输入规则表示式:");
String regex = console.nextLine();
out.print("输入要比较的文字:");
String text = console.nextLine();
print(match(regex, text));
} catch(PatternSyntaxException ex) {
out.println("规则表示式有误");
out.println(ex.getMessage());
}
}

private static List<String> match(String regex, String text) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
List<String> matched = new ArrayList<>();
while(matcher.find()) {
matched.add(String.format(
"从索引 %d 开始到索引 %d 之间找到符合文字 \"%s\"%n",
matcher.start(), matcher.end(), matcher.group()));
}
return matched;
}

private static void print(List<String> matched) {
if(matched.isEmpty()){
out.println("找不到符合文字");
}
else {
matched.forEach(out::println);
}
}
}

20145330第八周《Java学习笔记》

JDK8 API增强功能

  • String新增join()静态方法可以指定每个字符串间以逗号分隔进行连接。
  • Arrays上新增parallelPrefix()、parallelSetAll()与parallelSort()方法,parallelSort()方法,可以将指定的数组分为子数组并以平行化方式分别排序,然后再进行合并排序。

学习中的问题和解决方法

  • 在时间计算中,时区的计算是非常困难的,在新的时间与日期API中个,UTC偏移量与时区的概念是分开的,OffsetDateTime单纯代表UTC偏移量,使用ISO 8601,如果有LocalDateTIme、LocalDate、Localtime
  • 也可以在分别补齐必要信息后,取得UTC偏移量。
  • 在运行DateFormatDemo中,提示它是公共的,应该在该文件的.java中声明,代码中定义的本来就为public class,DateFormatDemo。之后去除public之后就能成功运行了。

学习感受

这周的任务相对之前轻松一些,所以也有更多的时间将知识梳理与弄明白。而且还有时间去复习其他科的知识,让我感到十分充实。希望可以一直保持状态,进入良好的学习循环中。需要我们学会使用日志API、了解国际化基础、认识JDK8增强功能等。通过前面几周的学习,java的核心知识与难点之前都已经学完了,后面的章节大概都是介绍一些类的应用。在以后的学习中,将会把重点放在实验博客的撰写上面,感觉实验才是检验学习的真正方法和途径。

代码托管截图

20145330第八周《Java学习笔记》
20145330第八周《Java学习笔记》

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时
第一周 200/200 2/2 20/20
第二周 300/500 2/4 18/38
第三周 500/1000 3/7 22/60
第四周 300/1300 2/9 30/90
第五周 200/1500 1/10 20/20
第六周 200/1700 2/12 18/108
第七周 200/1900 2/14 20/128
第八周 200/2100 2/16 20/148