文章目录
异常
在程序运行的过程中,出现的非正常情况,最后导致JVM的非正常停止。Java中有一个调用栈,有指向异常处理方法的指针,一个程序的所有异常都被收集在程序的某一段去处理。程序运行的时候,系统会把收集到的异常和异常处理指针所指向的处理类型逐个比较,找到相符的类型,转向相应的类型处理。
异常本身是一个类,产生异常就是创建异常对象并且抛出了一个异常对象(抛出异常)。java处理异常的方式就是中断处理。Jvm接收到异常对象的时候,会查找能处理这一异常代码,并把当前的对象交给它处理(捕获异常)
Throwable==Error(工程师不能处理,只能避免)+Exception(由于使用不当导致,但是可以避免)。
关键字
try,catch,finally,throw,throws
抛出异常throw
直接抛出异常类实类
throw new 异常类名(参数);
声明异常throws
把问题标识出来,报告给调用者。如果方法内部通过throw抛出了编译时异常,但是没有做捕获处理,那么必须通过throws声明,让调用者去处理。
修饰符 返回值类型 方法名(参数)throws 异常类名1,异常类名2...{}
捕获异常
Java对有异常的针对性语句进行捕获,可以对出现的异常进行指定方式的处理。
如果异常出现的化,会立刻终止程序。
(1)该方法不处理,而是声明抛出,由该方法的调用者来处理throws
(2) 该方法中用try-catch语句来处理异常。
try {
//编写可能出现的异常代码
}catch(异常类型 e){
//记录日志 打印异常信息 继续抛出异常
}
Throwable类定义了一些查看方法:
getMessage():获取异常的描述信息,原因(给用户看的时候,就显示错误原因)。
toString();获取异常的类型和异常描述信息。
printStackTree();打印异常的跟踪信息并且输出到控制台。
异常处理注意事项
finally:有一些特定的代码无论是否发生异常都需要执行。finally里面存放的代码块是一定会被执行的。
try{}catch{}finally{}
(1)如果父类抛出来多个异常,子类覆盖父类方法时,只能抛出相同的异常或者是它的子集。
(2)当多异常处理的时候,捕获处理,前边的类不能是最后边类的父类。应该首先处理子类异常。
//多个异常使用捕获
try{
//编写可能出现的异常代码
}catch(异常类型A e)
{
//当try出现A类型异常,就使用catch来捕获
//处理异常代码
}catch(异常类型B e)
{
}
(3)有多个catch字句的时候,最多只会执行其中一个catch语句中的异常处理代码
(4)子类方法抛出的异常可以是父类中抛出异常的子集,子类方法也可以不抛出异常,但是不能出现父类对应方法的throws语句没有异常的类型。
自定义异常
我们在实际生活中,根据自己的业务异常情况来定义异常类。
自定义一个业务逻辑异常LoginException,一个异常登陆类。
//模拟登录的时候用户名重复的异常
public class LoginException extends Exception{
public loginException()
{}
public loginException(String message)
{
//异常信息构造方法
super(message);
}
}
package com.kkb;
public class ExceptionDemo06 {
// 模拟数据库中已存在账号
private static String[] names = {"bill","hill","jill"};
public static void main(String[] args) {
//调用方法
try{
// 可能出现异常的代码
checkUsername("bill");
System.out.println("注册成功");//如果没有异常就是注册成功
}catch(LoginException e){
//处理异常
e.printStackTrace();
}
}
//判断当前注册账号是否存在
//因为是编译期异常,又想调用者去处理 所以声明该异常
public static boolean checkUsername(String uname) throws LoginException{
for (String name : names) {
if(name.equals(uname)){//如果名字在这里面 就抛出登陆异常
throw new LoginException("亲"+name+"已经被注册了!");
}
}
return true;
}
}
lombok常用注释
@Getter和@Setter
作用:生成成员变量的get和set方法。
写在成员变量上,指对当前成员变量有效。
写在类上,对所有成员变量有效。
注意:静态成员变量无效。
@ToString
作用:生成toString()方法。
注解只能写在类上。
@NoArgsConstructor和@AllArgsConstructor
@NoArgsConstructor:无参数构造方法。
@AllArgsConstructor:满参数构造方法。
注解只能写在类上。
@EqualsAndHashCode
作用:生成hashCode()和equals()方法。
注解只能写在类上。
@Data
作用:生成get/set,toString,hashCode,equals,无参构造方法
注解只能写在类上
新技术
Lambda 表达式
我们总是通过匿名内部类进行方法传递,java提供了Lambda的方法。
将函数本身作为参数传递给另外一个函数的变成方式,并且返回一个函数。
本质上是一个匿名函数。最后返回一个接口
public interface Num{
public int add(int a,int b);
}
//方法定义 参数列表 方法实现
Num num=(int a,int b)->{return a,b};
()->{System.out.println("你好");
每个Lambda表达式都能够隐式地赋值给函数式接口,再通过接口来调用Lambda表达式。
函数式编程
基本的函数接口:
Supplier<T> 生产者:无输入,生产出一个T类型的值
Consumer<T> 消费者:输入一个T类型的值,无输出
Function<T,R>函数:输入一个T类型的值,返回一个R类型的值
Predicate<T>断言:输入一个T类型的值,返回true或者false
Supplier
//生产出一个T类型的值
Supplier<Integer> supplier=()->10*10;
System,out,println(supplier.get());
//创建对象
Supplier<User> u=()->new User();
System.out.println(u.get().toString());
Consumer
//语句段写法
Consumer<String> cum1=(String x)->System.out.println(x);
//表达式写法
Consumer<String> cum2=x->System.out.println(x);
cum1.accept("hello");
//先调用cum1再调用cum2
cum1,andThen(cum2),accept(12);
Function<T,R>
Function<Integer,Integer> fun1=x->x+10;
fun1.apply(10);
fun1.compose(fun2).apply(10);//先执行fun2再去执行fun1
fun1.andThen(fun2).apply(10);//先执行fun1再去执行fun2
Predicate断言
Predicate<Integer> pre1=n->n>5;
pre1.test();
pre.negate().test(10);//取反 !
//添加条件
pre1.add(pre2).test(10);//并且 &
pre1.or(pre2),test(10);//or |
Stream式编程
List<Integer> List1=Array.asList(1,2,3,4,5);
//串行流 过滤出所有大于3的数字
List1.stream().filter(s->{
return s>3;
}}.foreach(x->System.out.println(Thread.currentThread().getName()+"\t"+x));
//并行流
List1.paralleStream().filter(s->{
return s<=3;
//循环输出 当前线程的名字+stream中的内容
}}.forEacn(x——>System.out.println(Thread.currentThread(),getName+"\t"+x));
方法引用
一种引用但是不执行方法的反思过hi。运行时候,方法引用会创建一个函数式的接口实例。
Consumer<String> con2=System.out::println;
con2.accept("hell0");
五种方式
引用对象的实例方法 对象::实例对象名
引用类的静态方法 类::静态方法名
引用类的实例方法 类::实例方法名
引用构造方法 类::new
数组引用 类型::new
集合使用
请添加图片描述