十二、Stream、异常体系、日志框架
创建不可变集合
-
不可变集合,就是不可被修改的集合
-
集合的数据项在创建的时候提供,并且在整生命周期种不可改变,否则报错
-
为什么要创建不可变集合?
-
-
或者当集合对象被不可信的库调用时,不可变形式是安全的
-
-
如何创建不可变集合?
-
在List、Set、Map接口中,都存在of方法,可以创建一个不可变的集合
-
方法名称 说明 static <E> List<E> of(E…elements) 创建一个具有指定元素的List集合 static <E> Set<E> of(E...elements) 创建一个具有指定元素的Set集合 static <K,V> Map<K,V> of(E...elements) 创建一个具有指定元素的Map集合
-
-
这个集合不能添加、不能删除、不能修改
-
Stream流
-
Stream流的概述
-
什么是Stream流?
-
在Java 8中,得益于Lambda所带来的函数式编程,引入了一个全新的Stream流概念
-
-
目的:用于简化集合和数组操作的API
-
Stream流式思想的核心:
-
先得到集合或者数组的Stream流(就是一根传送带)
-
把元素放上去
-
然后就用这个Stream流简化的API来方便的操作元素
-
-
-
Stream流的获取
-
Stream流的三类方法
-
获取Stream流
-
创建一条流水线,并把数据放到流水线上准备进行操作
-
-
中间方法
-
流水线上的操作。一次操作完毕之后,还可以继续进行其他操作
-
-
终结方法
-
一个Stream流只能由一个终结方法,式流水线上的最后一个操作
-
-
-
Stream操作集合的第一步是先得到Stream流,然后才能使用流的功能
-
集合获取Stream流的方式
-
可以使用Collection接口中的默认方法stream()生成流
-
名称 说明 default Stream<E> stream() 获取当前集合对象的Stream流
-
-
-
数组获取Stream流的方式
-
名称 说明 public static <T> Stream<T> stream(T[] array) 获取当前数组的Stream流 public static<T> Stream<T> of(T...values) 获取当前数组/可变数据的Stream流
-
-
-
Stream流的常用API
-
中间操作方法
-
名称 说明 Stream<T> filter(Predicate<? super T> predicate) 对数据流中的数据进行过滤 Stream<T> limit(long maxSize) 获取前几个元素 Stream<T> skip(long n) 跳过前几个元素 Stream<T> distinct() 去除流中重复的元素。依赖(hashCode和equals方法) static <T> Stream<T> concat(Stream a,Stream b) 合并a和b两个流为一个流
-
-
注意:
-
中间方法也成为非终结方法,调用完成后返回新的Stream流可以继续使用,支持链式编程
-
在Stream流中无法直接修改集合、数组中的数据。
-
-
Stream流的常见终结操作方法
-
名称 说明 void forEach(Consumer action) 对此流的每个元素执行遍历操作 long count() 返回此流中的元素数
-
-
注意:终结操作方法,调用完成后流就无法继续使用了,原因是不会返回Stream了
-
-
Stream流的综合应用
-
d_17.stream
-
-
收集Stream流
-
收集Stream流的含义:就是把Stream流操作后的结果数据传回到集合或者数组中去
-
Stream流:方便操作集合/数组的手段
-
集合/数组:才是开发中的目的
-
Stream流的收集方法
-
名称 说明 R collecct(Collector collector) 开始收集Stream流,指定收集器
-
-
Collectors工具类提供了具体的收集方式
-
名称 说明 public static <T> Collector toList() 把元素收集到List集合中 public static <T> Collector toSet() 把元素收集到Set集合中 public static Collector toMap(Function keyMapper,Function valueMapper) 把元素收集到Map集合中
-
-
异常处理
-
异常概述、体系
-
什么是异常
-
异常时程序在“编译”或者“执行”的过程中可能出现的问题,注意:语法错误不算在异常体系中
-
比如:数组索引越界、空指针异常、日期格式化异常……
-
-
为什么要学习异常?
-
异常一旦出现了,如果没有提前处理,程序就会退出JVM虚拟机而终止
-
研究异常并且避免异常,然后提前处理异常,体现的是程序的安全性,健壮性
-
-
异常体系
-
Throwable
-
Error
-
系统级别问题、JVM退出等,代码无法控制
-
-
Exception
-
java.lang包下,称为异常类,它表示程序本身可以处理的问题
-
RuntimeException及其子类
-
运行时异常,编译阶段不会报错。(空指针异常,数组索引越界异常)
-
-
除RuntimeExcepion之外的所有异常
-
编译时异常,编译期必须处理的,否则程序不能通过编译(日期格式化异常)
-
-
-
-
编译时异常和运行时异常
-
编译时异常(编译时出现),是在编译成class文件时必须处理的异常,也称之为受检异常
-
运行时异常(运行时出现),在编译成class文件不需要处理,在运行字节码文件时可能出现的异常
-
-
-
-
常见运行时异常
-
直接继承自RuntimeException或其子类,编译阶段不会报错,运行时可能出现的错误
-
运行时异常,一般是程序员业务没有考虑好或者是编程逻辑不严谨引起的程序错误
-
运行时异常示例
-
数组索引越界异常:ArrayIndexOutOfBoundsException
-
空指针异常:NullPointerException,直接输出没有问题,但是调用空指针的变量的功能就会报错
-
数学操作异常:ArithmeticException
-
类型转换异常:ClassCastException
-
数字转换异常:NumberFormatException
-
-
-
常见编译时异常
-
不是RuntimeException或其子类的异常,编译阶段就会报错,必须处理,否则代码不通过
-
编译时异常的作用:
-
是担心程序员的技术不行,在编译阶段就爆出一个错误,目的在于提醒不要出错
-
-
-
异常的默认处理流程
-
默认会再出现异常的代码那里自动的创建一个异常对象:ArithmeticException
-
异常会从方法中出现的点这里抛出给调用者,调用者最终抛出给JVM虚拟机
-
虚拟机接收到异常对象后,现在控制台直接输出异常栈信息数据
-
直接从当前执行的异常点干掉当前程序
-
后续代码没有机会执行了,因为程序已经死亡
-
-
编译时异常的处理机制
-
出现异常直接抛出去给调用者,调用者也继续抛出去
-
出现异常自己捕获处理,不麻烦别人
-
前两者结合,出现异常直接抛出去给调用者,调用者捕获处理
-
异常处理方式1--throws
-
throws:用在方法上,可以将方法内部出现的异常抛出去给本方法的调用者处理
-
这种方式并不好,发生异常的方法自己不处理异常,如果异常最终抛出去给虚拟机将引起程序死亡
-
抛出异常的格式:
-
方法 throws 异常1,异常2,异常3……{}
-
-
规范做法:
-
方法 throws Exception{}
-
-
-
异常处理方式2--try...catch...
-
监视捕获异常,用在方法内部,可以将方法内部出现的异常直接捕获处理
-
这种方式还可以,发生异常的方法自己独立完成异常的处理,程序可以继续往下执行
-
格式:
-
try{//监视可能出现异常的代码
-
}catch(异常类型1 变量){//处理异常
-
}catch(异常类型2 变量){//处理异常
-
}...
-
-
建议格式:
-
try{//可能出现异常的代码
-
}catch(exception e){
-
e.printStackTrace();//直接打印异常栈信息}
-
Exception可以捕获处理一切异常类型
-
-
-
异常处理方式3--前两者结合
-
方法直接将异常通过throws抛出去给调用者
-
调用者收到异常后直接捕获处理
-
-
-
运行时异常的处理机制
-
按照规范建议还是处理:建议在最外层调用处集中捕获处理即可
-
d_18.Test
-
-
异常处理使代码更稳健的案例
-
d_18.Test2
-
-
自定义异常
-
自定义异常的必要?
-
Java无法为这个世界上全部的问题提供异常类
-
如果企业想通过异常的方式来管理自己的某个业务问题,就需要自定义异常类了
-
-
自定义异常的好处:
-
可以使用异常的机制管理业务问题,如提醒程序员注意
-
同时一旦出现bug,可以用异常的形式清晰的指出出错的地方
-
-
自定义异常的分类
-
自定义编译时异常
-
定义一个异常类继承Exception
-
重写构造器
-
再出现异常的地方用throw new 自定义对象抛出
-
作用:编译时异常是编译阶段就报错,提醒更加强烈,一定要处理
-
-
自定义运行时异常
-
定义一个异常类继承RuntimeException
-
重写构造器
-
再出现异常的地方用throw new 自定义对象抛出
-
作用:提醒不强烈,编译阶段不报错,运行时才可能出现
-
-
-
日志框架
-
日志技术的概述
-
生活中的日志:生活中的日志就好比日记,可以记录你生活的点点滴滴
-
程序中的日志:程序中的日志可以用来记录程序运行过程中的信息,并可以永久存储
-
输出语句的弊端
-
信息只能展示在控制台
-
不能将其记录到其他的位置(比如文件、数据库)
-
想取消记录的信息需要修改代码才可以完成
-
-
日志技术具备的优势
-
可以将系统执行的信息选择性的记录到指定的位置(比如控制台、文件中、数据库中)
-
可以随时以开关的形式控制是否记录日志,无需修改代码
-
-
输入语句于日志技术的区别:
-
输出语句 日志技术 输出位置 只能是控制台 可以将日志信息写入到文件或者数据库中 取消日志 需要修改代码,灵活性比较差 不需要修改代码,灵活性比较好 多线程 性能较差 性能较好
-
-
-
日志技术体系结构
-
日志规范接口:
-
Commons Logging (简称:JCL)
-
Simple Logging Facade for Java(简称:slf4j)
-
-
日志实现框架
-
Log4j
-
JUL(java.util.logging)
-
Logback
-
其他实现
-
-
日志规范:一些接口,提供给日志的实现框架设计的标准
-
日志框架:牛人或者第三方公司已经做好的日志记录实现代码,后来者可以直接拿去使用
-
因为对Commons Logging的接口的不满意,有人就搞了SLF4J。因为对Long4J的性能不满意,有人就搞了Logback
-
-
Logback概述
-
Logback日志框架
-
Logback是由log4j创始人设计的另一个开源日志组件,性能比log4j要好
-
Logback是基于slf4j的日志规范实现的框架
-
-
Logback主要分为三个技术模块:
-
logback-core:logback-core模块为其他两个模块奠定了基础,必须有
-
logback-classic:它是log4j的一个改良版本,同时它完整实现了slf4j API
-
logbcak-access模块于Tomcat和Jetty等Servlet容器集成,以提供HTTP访问日志功能
-
-
-
Logback快速入门
-
d_19.Test
-
-
Logback配置详解-输出位置、格式设置
-
Logback日志输出位置,格式设置:
-
通过logback.xml中的<append>标签可以设置输出位置和日志信息的详细格式
-
通常可以设置2个日志输出位置:一个是控制台、一个是系统文件中
-
-
输出到控制台的配置标志
-
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
-
-
输出到系统文件的配置标志
-
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
-
-
-
Logback配置详解-日志级别设置
-
日志级别
-
级别程度依次是:TRACE<DEBUG<INFO<WARN<ERROR;默认级别是debug(忽略大小写),对应其方法
-
作用:用于控制系统中哪些日志级别是可以输出的,只输出级别不低于设定级别的日志信息
-
-
ALL和OFF分别是打开全部日志信息,及关闭全部日志信息
-
具体在<root level = "INFO">标签的level属性中设置日志级别
-
阶段实战
-
bean
-