javaEE进阶小结与回顾(四)

发布时间 2023-04-10 14:39:00作者: zFlame_5020

不可变集合

概念

  • 不可变集合,就是不可被修改的集合
  • 集合的数据项在创建的时候提供,并且在整个生命周期中都不可改变,否则报错

特点

  • 定义完成后不可以修改,或添加删除
  • 不需要考虑变化,节省时间和空间,比他们的可变形式有更好的内存利用率
  • 当集合被不可信的库调用时,不可变形式是安全的

如何创建

static <E> List <E> of(E...elements)
创建一个具有指定元素的List集合对象
static <E> Set <E> of(E...elements)
创建一个具有指定元素的Set集合对象
static <K,V> Map<K,V> of(K k1,V v1,...)
创建一个具有指定元素的Map集合对象

Stream

流的概述

  • 目的:用于简化集合跟数组操作,结合了Lambda表达式

特点

  • Stream流是一个来自数据源的元素队列,不是数据结构,并不存储数据;流中的数据来自原始的集合或数组,它只是按需计算
  • Stream流不会改变原始的数组或集合,但它可以将计算后的结果保存到一个新的集合中

流的获取

获取方式

1.单列集合
	使用Collection接口中默认方法stream()生成流
2.双列集合
	间接生成流,可以通过keySet或者entrySet获取一个Set集合,再获取	Stream流
3.数组
	Arrays中的静态方法stream生成流
4.同种数据类型的多个数据
	使用Stream.of(T...values)生成流

Stream流中有三类方法

获取流
	创建一条流水线,并把数据放大流水线上准备进行操作
中间方法
	流水线上的操作,一次操作完毕之后,还可以继续进行其他操作
终结方法
	一个Stream流只能有一个终结方法,是流水线上的最后一个操作

流的常用方法

常见中间操作方法

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流中无法直接修改集合,数组中的数据

常见终结操作方法

void forEach(Consumer action)
对此流的每个元素执行遍历操作
long count()
返回此流中的元素数

终结方法注意
  • 终结操作方法,调用完成后流就无法继续使用了,原因是不会返回Stream
  • 一个流只能用一次

Stream流的排序和转换方法(扩展)

<R> Stream<R> map (Function<? super T,? extends R> mapper)
将Stream流中的数据,从T类型转换成R类型,返回Stream

DoubleStream mapToDouble(ToDoubleFunction mapper)
从Stream流中的数据,提取Double类型的数据到DoubleStream流中返回
DoubleStream流提供的方法

OptionalDouble average()
返回流中数据的平均值对象,该对象可以调用getAsDouble()拿到平均值

总结

获取流
stream(),Arrays.stream(),Stream.of()
中间方法
filter(),skip(),limit(),distinct(),concat(),sort(),map(),mapToDouble()
终结方法
forEach(),count()
收集方法
collect (Collectors.toList());
collect (Collectors.toSet());

collect (Collectors.toMap(
          s->s,
          s->s.length()
));

收集流

含义

把Stream流操作后的结果,使用集合保存起来,方便后期再用

收集方法

R collect (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会终止进程,程序会退出
  • 研究异常并且避免异常,然后提前做好预案,提升程序的安全性,健壮性

java的异常体系和分类

异常体系

  • Throwable分为Error和Exception
  • Exception分为RuntimeException和非RuntimeException

Error

严重问题:硬件问题,内存溢出等,只能提前规避,不能使用代码处理,不需要关心

Exception

定义
在java.lang包下,被称为异常类,表示程序本身可以处理的问题
分支
  • RuntimeException及其子类
    运行时异常,编译阶段不会报错(空指针异常,数组索引越界异常),编译时可以不处理,但运行时可能出现异常

  • 除RuntimeException之外所有异常
    编译时异常,编译期必须处理,否则程序不能通过编译(日期格式化异常),也称之为受检异常

常见异常举例

编译期异常(必须处理,警示程序员注意)

日期解析异常
	ParseException

运行时异常(一般是程序员业务编程,逻辑不严谨引起的程序错误)

数组索引越界异常
	ArrayIndexOutOfBoundsException
空指针异常
	NullPointerException
	直接输出没问题,但调用空指针的变量功能会报错
数学操作异常
	ArithmeticException
类型转换异常
	ClassCastException
数字格式异常
	NumberFormatException

jvm默认的异常处理

  • 程序出现问题,我们不做任何处理,最终JVM会做默认处理
    • 将异常名称,原因,异常出现位置等详细信息输出到控制台
    • 从出现异常的位置开始,中断程序的执行

异常处理方式一 try catch

监视捕获异常,用在方法内部,可以将方法内部出现的异常直接捕获处理
优点是发生异常的方法自己独立完成异常处理,程序可以继续往下执行

格式
try{
     //监视可能出现的异常代码
} catch (异常类型1  变量){
    //处理异常
}catch  (异常类型2  变量){
   //处理异常
}...
Throwable类的方法

String getMessage()
返回此异常的详细消息字符串
String toString()
返回此异常的简短描述
void printStackTrace()
将此异常及其追踪输出至标准错误流

异常的处理方式二 throws声明抛出

当发生异常的方法自己没有权限或处理不了,可以声明抛出异常,让方法的调用者处理

throws:用在方法声明上,声明将方法内部出现的异常跑出去给方法的调用者处理
格式
方法名() throws 异常类1 , 异常类2 , 异常类3 ...{
}
特点

方法中异常后面的代码不能运行

程序员throw手动抛出异常

格式

throw 异常对象:
实例:
throw new RuntimeException();

作用

当方法的参数有误或者其他问题导致方法无法继续执行,可以使用throw语句来结束方法执行,并给调用者返回一个错误

自定义异常

必要性

企业自己的业务逻辑问题,如果希望用异常来描述,需要自定义异常类

好处

可以使用异常的机制来管理业务问题,引起程序员重视
一旦出现业务逻辑bug,比较容易定位和处理

步骤

  • 创建一个类继承Exception或RuntimeException
  • 重写构造器
  • 在方法中,出现异常的地方用throw new 自定义异常对象抛出

如何抛出自定义的异常

throw new 自定义异常类("错误信息");

JDK8日期类

新增与传统

传统
  • 设计不合理,使用不方便,很多都被淘汰
  • 都是可变对象,修改后会丢失最开始的时间信息
  • 线程不安全
  • 只能精确到毫秒
新增
  • 设计更合理,功能丰富,使用更方便
  • 都是不可变对象,修改后会返回新的时间对象,不会丢失最开始的时间
  • 线程安全
  • 能精确到毫秒,纳秒

概述

  • LocalDate:存储没有时间的日期,可存储生日
  • LocalTime:存储没有日期的时间,可存储开盘收盘时间
  • Instant:代表的是时间戳
  • DateTimeFormatter:用于做时间的格式化和解析的
  • Duration:用于计算两个"时间"间隔
  • Period:用于计算两个"日期"间隔

LocalDateTime:会存储类似'2022-12-03T11:30'的日期时间

没有构造方法,常用两个静态方法获取时间

public static LocalDateTime now()
从默认时区中的系统时钟获取当前日期时间
public static LocalDateTime of(int year,int month,int dayOfMonth,int hour,int minute,int second)
从年,月,日,小时,分钟,秒获得LocalDateTime的实例,将纳秒设置为零

LocalDateTime获取方法
	public int get Year()
		获取年
	public int getMonthValue()
		获取月份(1-12)
	public int getDayOfMonth()
		获取月份中的第几天(1-31)
	public int getDayOfYear()
		获取一年中的第几天(1-366)
	public DayOfWeek getDayOfWeek()
		获取星期
	public int getMinute()
		获取分钟
	public int getHour()
		获取小时
LocalDateTime计算
	public LocalDateTime plusYears(long years)
		添加或减去年
	public LocalDateTime plusMonths(long months)
		添加或者减去月
	public LocalDateTime plusDays(long days)
		添加或者减去日
	public LocalDateTime plusHours(long hours)
		添加或减去时
	public LocalDateTime plusMinutes(long minutes)
		添加或减去分
	public LocalDateTime plusSeconds(long seconds)
		添加或减去秒
	public LocalDateTime plusWeeks(long weeks)
		添加或减去周
LocalDateTime类

格式化(日期对象-->String)
String format(DateTimeFormatter formatter)
解析(String-->日期对象)
Public static LocalDateTime parse(CharSequence text,DateTimeFormatter)
** 静态方法!**

DateTimeFormatter类

没有构造方法,常用以下静态方法获取日期格式化对象
public static DateTimeFormatter ofPattern(String pattern)
使用指定的模式创建格式化对象

代码块

在java类下,使用{}括起来的代码被称为代码块

静态代码块

格式

static{} 写在类中

特点

需要通过static关键字修饰,随着类的加载而加载,并且自动触发,只执行一次

使用场景

在类加载的时候做一些静态数据初始化的操作,以便后续使用

构造代码块(了解,不太用)

格式

{} 写在类中

特点

每次创建对象,调用构造器执行时,都会执行该代码块中的代码,并且在构造器执行前执行

使用场景

提高构造方法中代码的复用性

File类

概述

  • File类是文件和目录路径名的抽象表示

  • 对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已,它可以是存在的,也可以是不存在的

  • File类提供了诸如:创建文件(文件夹),删除文件(文件夹),获取(文件大小,最后修改时间),判断(路径是否存在)等

File类创建对象

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

两种路径

绝对路径:从盘符开始
File file1 = new File("D:\\tiheima\\a.txt");

相对路径:不带盘符
File file3 = new File("a.txt");
默认到当前工程project下寻找文件

File类常用方法

判断文件类型,获取文件信息
	public boolean isDirectory()
		判断此路径表示的File是否为文件夹
	public boolean isFile()
		判断此路径名表示的File是否为文件
	public boolean exists()
		判断此路径名表示的File是否存在
	public long length()
		返回文件的大小(字节数量)
	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方法默认只能删除文件和空文件夹,直接删除不走回收站
遍历文件夹
遍历功能

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

listFiles方法注意事项
  • 当文件夹不存在时,返回null
  • 当文件对象是文件时,返回null
  • 当文件对象是一个空文件夹时,返回一个长度为0的数组
  • 当文件对象是一个文件夹时,会将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
  • 当没有权限访问该文件夹时,会返回null

递归

概述与格式

方法直接或间接调用自己的形式称为方法递归(recursion)

  • 直接递归
    方法体内调用方法本身
    printNum(){printNum();}

  • 间接递归
    a(){b();} b(){a();}

  • 死递归
    如果递归没有写出口,会出现死递归,导致栈内存溢出的现象

  • 算法流程与核心要素

  • 把一个复杂的问题层层分解为一个与原问题相似的但规模较小的问题

  • 最后通过小问题的解决,将结果一层层合并,从而得到原始问题的结果

  • 递归思想:分解与合并

写递归的步骤

  • 写一个方法,明确参数和返回值
    int f(n){...};

  • 找规律
    f(n) = n*f(n-1);

  • 写出口
    f(n) = if(n==1) return 1;