Java进阶3(Stream流+ 异常+日志+I/O)

Stream流+ 异常+日志+I/O

Stream

作用   简化集合、数组操作的API  结合了Lambda表达式

使用  先得到集合或数组的Stream流,把元素放上去,然后用这个Stream流简化的API来方便操作元素

Stream流的三类方法

获取stream流    

创3建一条流水线,并把数据放到流水线上准备操作

中间方法

流水线上的操作,一次操作完毕后,还可继续其他操作   

终结方法

一个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()   去除流中重复的元素

Stream<T>  map   加工方法    第一个参数  原材料  第二个参数  加工后的结果

static <T> Stream<T> concat(Stream a,Stream b)   合并a和b两个流为一个流

中间方法也成为非终结方法,调用完成后返回新的Stream流可以继续使用,支持链式编程

在Stream流中无法直接修改集合、数组中的数据

Stream流常见的终结操作方法

void forEach(Consumer acton) 对此流的每个元素执行遍历操作

long count()  返回流中元素数          【只能用long类型来接,因为它认为集合元素会很多】

Stream流的收集操作

收集Stream流的含义:就是把Stream流操作后的结果数据转回到集合或者数组中去

Stream流:方便操作集合/数组的手段

集合/数组:才是开发中的目的

Stream流的收集方法

R collect(Collector collector) 开始收集Stream流,指定收集器

Collectors工具类提供了具体的收集方式

public static <T> Collector toList()  把元素收集到List集合中

public static <T> Collector toSet()  把元素收集到Set集合中

public static <T> Collector toMap(Function keyMapper,Function valueMapper)  把元素收集到Map集合中

注意:流只能使用一次

因为zhangList已经收集到List集合,所以不能再收集到Set集合中去

但是我们把注释的那个zhangSet打开,如下,换成zhangSet,就ok

异常

异常是程序在编译或者执行的过程中可能出现的问题   注意 语法错误不算在异常体系中

比如  数组索引越界 空指针异常 日期格式化异常

异常一旦出现,如果没有提前处理,程序就会退出JVM虚拟机而终止

异常体系

Error系统级别问题、JVM退出,代码无法控制

Exceptionjava.lang包下,称为异常类,它表示程序本身可以处理的问题

RuntimeException及其子类:运行时异常,编译阶段不会报错(空指针异常,数组越界异常)

RuntimeException之外的所有异常:编译时异常,编译阶段必须处理的,否则程序不能通过编译(日期格式化异常)

异常分类

编译时异常:没有继承RuntimeException的异常,编译阶段就会报错

运行时异常:继承自RuntimeException的异常或其子类,编译阶段不报错,运行时会报错

运行时异常(归根到底是程序员水平不行)

直接继承自RuntimeException或者其子类,编译阶段不会报错,运行时可能会出现的错误

示例 

数组越界异常  ArrayIndexOutOfBoundsException

空指针异常  NullPointerException 直接输出没有问题,但是调用空指针的变量的功能就会报错

数学操作异常ArithmeticException

类型转换异常ClassCastException

数字转换异常NumberFormatException

编译时异常

不是RuntimeException或者其子类的异常,编译阶段就报错,必须处理,否则代码不通过

处理方法  在划红线的地方 alt+enter  选第一个,即可抛出异常

作用

担心程序员技术不行

编译异常处理

默认处理

默认会在出现异常的代码那里自动创建一个异常对象:ArithmeticException

默认会从方法中出现的点这里抛出异常,调用者最终抛出给JVM虚拟机

虚拟机接收到异常对象后,先在控制台直接输出异常栈信息数据

直接从当前执行的异常点干掉当前程序

后续代码没有机会执行了,因为程序已经死亡

其它处理机制

方式1  throws

throws 用在方法上,可以将方法内部出现的异常抛出去给方法的调用者处理

这种方式并不好,发生异常的方法自己不处理异常,如果异常最终抛出去给虚拟机将引起程序死亡

抛出异常格式  方法 throws 异常1  异常2  异常3..{

}

规范做法  方法 throws Exception{

}                                     -------->这种方法只写一个Exception就ok

方式2  try...catch...

监视捕获异常,用在方法内部,可以将方法内部出现的异常直接捕获处理

这种方式还可以,发生异常的方法自己独立完成异常的处理,程序可以继续往下执行

try{

}catch(异常类型 1 变量){

}catch(异常类型2 变量){

}...

建议格式  按Ctrl+alt+t选中可能会出现问题的代码,然后选择try/catch (此时不直接用Ctrl+enter因为想把多行代码放到try里面所以选中了多行代码,不能再用这个快捷键),代码会全部放在try里面,然后将catch后面的改为Exception,使其可以接受一切类型的异常,不用写多个catch

try{

}catch(Exception e){

e.printStackTrace();

}  Exception可以捕获处理一切异常类型

如下:程序即使出现了问题,也会把程序执行完,不至于崩溃

方式3 上面两种的结合  在方法里抛出异常,即ctrl+enter 时选第一个,然后再main方法里,ctrl+alter选第二个try catch

好处  调用方法的地方知道自己哪里错了,其实和上面都一样,三种我们具体选那种看公司规范

运行异常处理

运行时异常编译阶段不会报错,是运行时才可能出错的,所以编译阶段不处理也可以

按照规范建议还是处理 建议在最外层调用出集中捕获处理即可

自定义编译异常

定义一个异常类继承 Exception

重写构造器

在出现异常的地方用throw new 自定义对象抛出

作用  编译时异常时编译阶段就报错,提醒更加强烈,一定要处理

注意  throw  在方法内部直接创建一个异常对象,并从此点抛出   throws 在方法的申明上,抛出方法内部的异常

左边是重写的异常,右边是实现

自定义运行异常

定义一个异常类继承 RuntimeException

重写构造器

在出现异常的地方用throw new 自定义对象抛出

作用  提醒不强烈,编译阶段不报错,运行时才可能出现

左边是重写的异常,右边是实现

日志技术

程序中的日志可以用来记录程序运行过程中的信息,并可以进行永久存储

日志技术具备的优势

                         输出语句                                                               日志技术

输出位置      只能是控制台                                           可以将日志信息写入到文件或者数据库中

取消日志   需要修改代码,灵活性比较差                         不需要修改代码,灵活性比较好                      

多线程            性能较差                                                                     性能较好

体系结构

日志规范接口  Commons Logging(JCL)              Simple Logging Facade for Java(slf4j)

日志实现框架  Log4j   JUL(Java.util,logging) logback  其他实现

日志规范  一些接口,提供给日志实现框架设计的标准

日志框架 已经做好的日志记录实现代码

因为对Commons Logging(JCL)不满意,有人做了  Simple Logging Facade for Java(slf4j),因为对  Log4j不满意,有人就搞了 logback

Logback日志框架分为三个技术模块

logback-core logback-core模块为其他两个模块奠定了基础,必须有

logback-class 它是log4j的一个改良版本,同时它完整实现了slf4j API

logback-access 模块与Tomcat 和Jetty等Servlet容器集成,以提供HTTP访问日志功能

Logback快速入门

导入Logback日志技术到项目中,用于记录系统的日志信息

1 在项目下新建文件夹lib,导入Logback相关的jar包到该文件夹下,并添加到项目依赖库中(选中三个然后右键选add as library)

2 将Logback的核心配置文件logback.xml直接拷贝到src目录下

3  在代码中获取日志对象(写的时候最好在main方法底下写,会有提示,写完后再移到上面)

Logback日志输出位置、格式设置

通过logback.xml中的<append>标签可以设置输出位置和日志信息的详细格式

通常可以设置2个日志输出位置:一个控制台、一个是文件系统文件中

输出到控制台的配置标志

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">

输出到系统文件的配置标志

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">

日志级别

级别程度依次是:TRACE<DEBUG<INFO<WARN<ERROR 默认级别是debug(忽略大小) ,对应其方法

作用:用于控制系统中哪些日志级别是可以输出的,只输出级别不低于设定级别的日志信息

ALL和OFF 分别是打开全部日志信息,及关闭全部日志信息

具体在<root level="INFO">标签的level属性中设置日志级别

------------------

File类概述

File类在包java.io.File下,代表操作系统的文件对象(文件,文件夹)

File类提供了诸如:定位文件,获取文件本身的信息、删除文件、创建文件(文件夹)等功能  但是不能读写文件内容

File 对象可以定位文件和文件夹

File封装的对象仅仅是一个路径名,这个路径可以是绝对路径,也可以是不存在的

File类创建对象

public File(String pathname)  根据文件路径创建文件对象  ---> 一般用这种

public File(String parent ,String child) 从父路径和子路径名字符串创建文件对象

public File(File parent,String child) 根据父路径对应文件对象和子路径名字符串创建文件对象

认真看下面的代码及注释

File类的API

判断文件类型、获取文件信息功能

public boolean isDirectory() 测试此抽象路径表示的File是否为文件夹

public boolean isFile()         测试此抽象类表示的File是否为文件

public boolean exists()        测试此抽象路径名表示的File是否存在

public String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串

public String getPath()             将此抽象路径名转换为路径名字符串

public String getName()           返回此抽象路径名表示的文件或文件夹的名称

public long lastModified()         返回文件最后修改的时间毫秒值

创建文件功能

public boolean createNewFile()  创建一个新的空的文件

public boolean mkdir()  只能创建一级文件

public boolean mkdirs() 可以创建多级文件

删除文件功能

public boolean delete()  删除此抽象路径名表示的文件空文件夹

注意

delete方法直接删除不走回收站;delete方法默认只能删除空文件夹

File类的遍历功能

public String[] list()  获取当前目录下所有的"一级文件名称"到一个字符串数组中去返回

public File[] listFiles() 获取当前目录下所有的"一级文件对象"到一个文件对象数组中去返回

listFiles注意事项

当调用者不存在时,返回null

当调用者是一个文件时,返回null

当调用者是一个空文件夹时,返回一个长度为0的数组

当调用者是一个有内容的文件夹时,将里面的所有文件和文件夹的路径放在File数组中返回

当调用者是一个有隐藏文件的文件夹时,将里面的所有文件和文件夹的路径放在File数组中返回,包含隐藏

方法的递归

方法直接或间接调用自己的编程技巧称为递归

什么是递归死循环

递归的方法无限次调用自己,无法终止,出现内存栈溢出

递归解决问题的思路

把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解

递归问题核心三步骤(以求1-n的阶乘问题举例)

递归的公式   f(n)= f(n-1)*n;

递归的终结点  f(1)

递归的方向必须走向终结点

上面针对规律化的递归,还有非规律化的递归 例如文件搜索  买啤酒问题

文件搜索

先定位出的应该是一级文件对象

遍历全部一级文件对象,判断是否是文件

如果是文件,判断是否是自己想要的

如果是文件夹,需要继续递归进去重复上述过程

买啤酒问题(2元买一瓶 4个盖换一瓶  2个瓶换一瓶  问10元最多买几瓶 剩几个瓶  几个盖)

字符串常见的字符底层组成是什么样的?

英文和数字等在任何国家的字符集中都占1个字节

GBK字符中一个中文字符占2个字节

UTF-8编码中一个中文一般占3个字节

编码前的字符集和编码后的字符集有什么要求?

必须一致,否则会出现中文字符乱码

字符集的编码解码操作

String编码  

byte[] getBytes() 使用平台的默认字符集将该 String 编码为一系列字节,将结果存储到新的字节数组中

byte[] getBytes(String charsetName) 使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中

 String解码 

String(byte[] bytes)使用平台的默认字符集将指定的字节数组来构造新的String

String(byte[] bytes,String charsetName)通过指定的字符集解码指定的字节数组中来构造新的String

结果分析

前三个数字是 a b c 的 后面十个每两个一组分别代表一个汉字(GBK是如此,如果为utf-8,则有18个字符,前3个是 a b c 的,十五个每三个一组表示汉字)

I/O

I/O流也称为输入、输出流,就是用来读写数据的

概述

I 表示input,是数据从硬盘文件读入到内存的过程,称之为输入,负责读

O表示output,是内存程序的数据从内存写到硬盘文件的过程,称之为输出,负责写

分类

总结流的四大类

字节输入流:以内存为基准,来自磁盘文件/网络的数据以字节的形式读入到内存中去的流称为字节输入流

字节输出流:以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中去的流称为字节输出流

字符输入流:以内存为基准,来自磁盘文件/网络的数据以字符的形式读入到内存中去的流称为字节输入流

字符输出流:以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络中去的流称为字节输出流

文件字节输入流(每次读取一个字节)                                                           read()返回的是读取的那个字节是多少比如96

文件字节输入流(每次读取一个字节数组)                           read(byte[] buffer) 返回的是读取的数量  比如 3

左边是普通一个一个的写     右边是用循环

避免乱码问题

自己定义一个字节数组与文件的大小一样大,然后使用读取字节数组的方法,一次性读取完成

.length返回的是long类型,得强转一下

文件字节输出流

流的关闭与刷新

注意

字节输出流如何实现数据追加(因为默认是用新的数据将旧的数据全部覆盖)

在后面加true之后,就的数据不会被清除

字节输出流如何实现写出去的数据能换行

os.write("\r\n".getBytes())

如何让写出的数据能成功生效

flush() 刷新数据后流依旧可以继续使用

close()方法是关闭流,关闭包含刷新,关闭后流不可以继续使用了

文件拷贝

他可以复制任何东西,包括视频、文档等,因为所有的都是以字节组成的

try-catch-finally

finally在异常处理时提供finally来执行所有清除操作,比如说IO流中的释放资源

特    点 :被finally控制的语句最终一定会执行,而且比return先执行,除非JVM退出(        System.exit(0);       )

异常处理标准格式:try-catch-finally

作用

可以在finally中结束流操作,因为如果像上面文件拷贝那样结束流,很有可能在结束流操作前遇到错误,导致其不能正常结束流操作

而放在finally中,它一定会被执行

上面是普通的解决办法,比较繁琐,下面是JDK7的改进方案

try-with-resource

文件字符输入流(每次读取一个字符)

文件字符输入流(每次读取一个字符数组)

文件字符输出流

注意点和上面 字节输出流 类似,直接拷贝

字节输出流如何实现数据追加 在后面加true之后,就的数据不会被清除

字节输出流如何实现写出去的数据能换行

os.write("\r\n")

如何让写出的数据能成功生效

flush() 刷新数据后流依旧可以继续使用

close()方法是关闭流,关闭包含刷新,关闭后流不可以继续使用了

字节流 字符流 如何选择使用

字节流适合做一切文件数据的拷贝(音视频 文本)

字节流不适合读取中文内容输出

字符流适合做文本文件的操作(读写)

缓冲流

缓冲流也成为高效流,或者高级流,之前学习的字节流可以称为原始流

作用:缓冲流自带缓冲区,可以提高原始字节流、字符流读写数据的性能

字节缓冲流性能优化原理

字节缓冲输入流自带了8kb缓冲池,以后我们直接从缓冲池读取数据,所以性能较好

字节缓冲输出流自带了8kb缓冲池,数据就直接写入到缓冲池中去,写数据性能极高

字节缓冲流

字节缓冲输入流:BufferedInputStream,提高了字节输入流读取数据的性能,读写功能上并无变化

字节缓冲输出流:BufferedOutputStream,提高了字节输入出流读取数据的性能,读写功能上并无变化

例子

字符缓冲输入流:BuffereReader

作用:提高字符输入流读取数据的性能,除此之外多了按照行读取数据的功能

字符缓冲输出流:BufferedWriter

作用:提高字符输出流写取数据的性能,除此之外多了换行功能

转换流

问题引出:字符直接读取文本内容

必须文件和代码编码一致才不会乱码        如果文件和代码编码不一致,读取将出现乱码

解决  字符输入转换流  字符输出转换流

字符输入转换流  

InputStreamReader,可以把原始的字节流按照指定编码转换成字符输入流

作用

可以解决字符流读取不同编乱码的问题

字符输出转换流

OutputStreamWriter,可以把字节输出流按照指定编码转换成字符输出流

作用  可以指定编码把字节输出流转换成字符输出流,从而指定写出去的字符编码

对象序列化

作用:以内存为基准,把内存中的对象存储到磁盘文件中去,成为对象序列化

对象序列化用到哪个流

序列化对象的要求

对象必须实现序列化接口

对象反序列化

作用:以内存为基准,把存储到磁盘文件中去的对象数据恢复成内存中的对象,成为对象反序列化

对象反序列化用到哪个流

打印流

作用:打印流可以实现方便、高效的打印数据到文件中。打印流一般指 PrintStream PrintWriter

 PrintStream

可以实现打印什么数据就是什么数据,例如打印整数97 写出去就是97  打印boolean 的true 写出去就是true

PrintWriter

PrintStream 和  PrintWriter 的区别

打印数据功能上(println)是一模一样的,都是使用方便,性能高效

PrintStream 继承自字节输出流OutputStream,仅支持写字节数据的方法

PrintWriter  继承自字符输出流Writer ,仅支持写字符数据出去

输出语句重定向

属于打印流的一种应用,可以把输出语句的打印位置改到文件

其实System.out.println就是一种输出流,将内容输出到控制台

如下,只打印前两句到控制台,而下面两句在log.txt文件中

Properties属性集对象

其实就是一个Map集合,但我们一般不会当集合使用,因为HashMap更好用

Properties核心作用

Properties代表的是一个属性文件,可以把自己对象中的键值对信息存入到一个属性文件中去

属性文件  后缀是 .properties 结尾的文件,里面的内容是key=value 后续做系统配置信息的

使用Properties 把键值对信息存入到属性文中去

使用Properties读取属性文件中的键值对信息

commons-io框架  是阿帕奇公司研发

完成功能更简单  例子如下,远远不止如此,了解一下,以后用到在查

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值