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的静态成员指定信息层级,例如:
- Logger:注意无法使用构造方法生成Logger对象
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 訊息");
}
}
- 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 讯息");
}
}
- 使用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 信息");
}
}
- 使用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字符对字符串进行切割:
- 字面意义字符
- 字符类
- 贪婪、逐步、独吐量词
- 边界比较
分组与参考
- 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\".");
}
}
}
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);
}
}
}
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的核心知识与难点之前都已经学完了,后面的章节大概都是介绍一些类的应用。在以后的学习中,将会把重点放在实验博客的撰写上面,感觉实验才是检验学习的真正方法和途径。
代码托管截图
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 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 |