20145330第八周《Java学习笔记》

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 訊息");
    	}
	}

  • 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
posted @ 2016-04-24 23:22  20145330孙文馨  阅读(158)  评论(2编辑  收藏  举报