(1)异常
代表程序出现的问题
-
异常体系 Throwable Error 代表的系统级别错误 (属于严重问题),Error是给sun公司自己用的,我们了解即可 Exception 代表异常,程序可能出现的问题,我们通常会用Exception以及它的子类来封装程序出现的问题 RuntimeException 运行时异常(非受检异常),例如数组索引越界、空指针、数学运算异常等 其他Exception 编译时异常(受检异常),例如解析异常
-
JVM默认处理是常的方式 1. 打印异常信息 2. 立即结束程序(异常出现后,如果不处理,程序是无法继续向下运行的)
public class Demo1 {
public static void main(String[] args){
//1. 运行时异常(非受检异常),例如数组索引越界、空指针、数学运算异常等
//1-1 数组索引越界
int[] arr = {29,38,11};
// System.out.println(arr[3]);
//1-2 空指针
String str = null;
System.out.println(str.length());
//1-3 数学运算
int i =1/0;
System.out.println(i);
//2. 编译时异常(受检异常),例如解析异常
//日期格式解析异常
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
sdf.parse("2019");
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("程序继续向下运行");
}
}
-
异常处理的方案1--抛异常 在Java的方法调用中,如果一个方法中出现了异常,本方法自己不处理,默认是会抛给调用方法去处理的 此时要注意的是,如果发生的是非运行时异常,需要在方法上明确使用throws关键字声明抛出
-
格式 public void 方法名 throws 异常1 ,异常2 ,异常3 ..{ 方法体 throw new Exception()
public class Demo2 {
public static void main(String[] args) throws ParseException {
int []arr = {1,2,3};
System.out.println(arr[5]);
String str = null;
//System.out.println(str.length());
new SimpleDateFormat("yyyy-MM-dd").parse("2019-09-09");
}
}
-
处理的方案2--捕获异常 直接在当前方法,发生异常的代码外使用try--catch--结构捕获并处理异常 异常处理后,后续的代码是可以继续执行的
-
格式 public void 方法名{ try{ // 方法体 }catch(异常类型1 变量){ // 处理异常 }catch(异常类型2 变量){ // 处理异常 } }
public class Demo3 {
public static void main(String[] args) {
print();
}
public static void print(){
//1.运行时异常
String srt = null;
//System.out.println("字符串长度:" + srt.length());
try {
//java代码,jdk会监控try中的代码,一旦出现指定类型的错误,会进入到catch中做容错处理
System.out.println("字符串长度:" + srt.length());
new SimpleDateFormat("yyyy-MM-dd").parse("2019");
}catch (Exception e){
e.printStackTrace();//打印堆栈异常信息
System.out.println("字符串为空,长度为0");
}
}
}
-
自定义异常 Java无法为这个世界上全部的问题都提供异常类来代表,如果以后我们自己写的代码中的某种问题, 想通过异常来表示,以便用异常来管理该问题,那就需要自己来定义异常类了。
-
自定义运行时异常 1、定义一个异常类,继承RuntimeException 2、在类中提供构造函数 3、在需要抛出异常的地方使用throw关键字 抛出异常类的对象
-
public class Demo4 { public static void main(String[] args) { //模拟用户登录,用户名:admin,密码123456 System.out.println(login("admin","123456")); } //设置登录的方法 public static String login(String username,String password) { if (!username.equals("admin")) { //1.用户名错误,用户登录失败 throw new LoginException("用户名错误,用户登录失败"); } else if (!password.equals("123456")) { //2.用户密码错误,用户登录失败 throw new LoginException("用户密码错误,用户登录失败"); } else { //3.用户登录成功,返回用户信息 return "用户登录成功,用户名" + username; } } } //自定义运行时异常类 class LoginException extends RuntimeException{ //有参构造 public LoginException(String message) { super(message); } }
-
自定义异常 Java无法为这个世界上全部的问题都提供异常类来代表, 如果以后我们自己写的代码中的某种问题, 想通过异常来表示,以便用异常来管理该问题,那就需要自己来定义异常类了。
-
自定义编译时异常 1、定义一个异常类,继承Exception 2、在类中提供构造函数 3、在需要抛出异常的地方使用throw关键字 抛出异常类的对象
-
注意 编译时异常,在编写代码的过程中必须手动处理
-
异常的作用 1、异常是用来查找系统bug 的关键参考信息 2、异常可以作为方法内部一种特殊的返回值,以便通知上层调用者,代码底层的执行情况
public class Demo5 {
public static void main(String[] args) throws LoginException2{
//模拟用户登录,用户名:admin,密码123456
System.out.println(login("admin","1023456"));
}
//设置登录的方法
public static String login(String username,String password) throws LoginException2 {
if (!username.equals("admin")) {
//1.用户名错误,用户登录失败
throw new LoginException2("用户名错误,用户登录失败");
}else if (!password.equals("123456")) {
//2.用户密码错误,用户登录失败
throw new LoginException2("用户密码错误,用户登录失败");
}else {
//3.用户登录成功,返回用户信息
return "用户登录成功,用户名" + username;
}
}
}
//自定义编译时异常类
class LoginException2 extends Exception {
public LoginException2(String message) {
super(message);
}
}
(2)Lambda
-
Lambda表达式 是JDK8开始新增的一种语法形式,主要用来简化匿名内部类代码的书写
-
Lambda格式 (被重写方法的参数列表)->{ 被重写方法的方法体; }
-
Lambda使用前提 Lambda只能操作函数式接口(有且仅有一个抽象方法的接口,被FunctionalInterface注解修饰)
public class Demo1 {
public static void main(String[] args) {
//匿名内部类操作接口
Person person = new Person() {
@Override
public void eat() {
System.out.println("吃饭");
}
};
person.eat();
//Lambda简化
Person person1 = () -> {
System.out.println("吃软饭");};
person1.eat();
System.out.println("===========================================");
//匿名内部类操作抽象类
Animal animal = new Animal() {
@Override
void eat() {
System.out.println("狗吃肉脯");
}
};//无法使用Lambda简化
animal.eat();
}
}
//接口
interface Person {
void eat();
}
//抽象类
abstract class Animal {
abstract void eat();
}
public class Demo2 {
public static void main(String[] args) {
//调用test方法,最后打印乌鸦喝水
Bird bird = () -> System.out.println("乌鸦喝水");
bird.drink();
}
}
interface Bird {
//无参数无返回值
void drink();
}
public class Demo3 {
public static void main(String[] args) {
//调用test方法, 最后显示 哈哈哈哈
test( info -> System.out.println(info));
}
public static void test(Printer printer) {
printer.fun("哈哈哈哈");
}
}
interface Printer {
void fun(String info);
}
public class Demo4 {
public static void main(String[] args) {
//调用test完成 a+b 的计算
test((a,b) -> a+b);
}
public static void test(Calculator calculator) {
System.out.println("运算结果:" + calculator.add(10, 20));
}
}
interface Calculator {
int add(int a, int b);
}
(3)方法引用
-
JDK8新特性,方法引用 主要用来简化、替换Lambda表达式
-
方法引用分类 1、静态方法的引用 2、实例方法的引用 3、特定类型方法的引用 4、构造器引用
-
小提示 先写匿名内部类,发现能化再化(写的多了就热练了)
-
1、静态方法的引用: 某个Lambda只是调用一个静态方法,并且前后参数一致,即可使用 类名::静态方法 2、实例方法的引用: 某个Lambda只是调用一个实例方法,并且前后参数一致,即可使用 对象名::实例方法
-
public class Demo1 { public static void main(String[] args) { Student[] students = new Student[4]; students[0] = new Student("蜘蛛精", 169.5, 23); students[1] = new Student("紫霞", 163.8, 26); students[2] = new Student("紫霞", 163.8, 27); students[3] = new Student("至尊宝", 167.5, 24); //1、 使用匿名内部类完成按照年龄排序功能 // Arrays.sort(students, new Comparator<Student>() { // @Override // public int compare(Student o1, Student o2) { // return MyComparator.compareByAge1(o1, o2); // } // }); //2、 使用Lambda完成按照年龄排序功能 // Arrays.sort(students, (Student o1, Student o2) -> { // return MyComparator.compareByAge1(o1, o2); // }); //3、 将升序排列的逻辑,封装到一个静态方法中, 调用完成 //1- 内部类中方法。调用其他的静态方法 //2- 调用静态方法时,参数列表和内部类方法参数列表顺序一致 //3- 工具类 :: 方法名 // Arrays.sort(students,MyComparator :: compareByAge1); //4、 将升序排列的逻辑,封装到一个实例方法中, 调用完成 //1- 内部类中方法。调用其他的实例方法 //2- 调用静态方法时,参数列表和内部类方法参数列表顺序一致 //3- new 对象() :: 方法名 Arrays.sort(students, new MyComparator() :: compareByAge2); //打印效果 System.out.println(Arrays.toString(students)); } } class Student { private String name; private double height; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public double getHeight() { return height; } public void setHeight(double height) { this.height = height; } public Student(String name, double height, int age) { this.name = name; this.height = height; this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", height=" + height + ", age=" + age + '}'; } } class MyComparator { public static int compareByAge1(Student s1, Student s2) { return s1.getAge() > s2.getAge() ? 1 : -1; } public int compareByAge2(Student s1, Student s2) { return s1.getAge() > s2.getAge() ? 1 : -1; } }
3、特定类型方法的引用: 如果某个Lambda只是调用一个实例方法,并且前面参数列表中第一个参数作为主调,后面的参数作为入参,即可使用 类型::方法 借助string类的compareToIgnoreCase方法,忽略大小写比较字符内容
public class Demo2 {
public static void main(String[] args) {
String[] names = {"boby", "angela", "Andy", "dlei", "caocao", "Babo", "jack", "Cici"};
//1、使用匿名内部类对数组进行排序,规则是忽略大小写进行排序(String int compareToIgnoreCase(String str))
Arrays.sort(names, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
});
System.out.println(Arrays.toString(names));
//2、 Lambda简化上述代码
Arrays.sort(names, (String o1, String o2) -> {
return o1.compareToIgnoreCase(o2);
});
System.out.println(Arrays.toString(names));
//3、使用特定类型方法的引用 简化Lambda代码
// 类型 :: 方法
Arrays.sort(names, String::compareToIgnoreCase);
//打印结果
System.out.println(Arrays.toString(names));
}
}
4、构造器引用 如果某个Lambda表达式里只是在创建对象,并且前后参数情况一致,就可以使用构造器引用 类名::new
public class Demo3 {
public static void main(String[] args) {
CreateCar createCar = null;
//1. 使用匿名内部类方式调用CreateCar实现对象的创建
// createCar = new CreateCar() {
// @Override
// public Car create(String brand, double price) {
// return new Car(brand, price);
// }
// };
//2. 使用Lambda优化上面代码
//createCar = ( brand, price) -> new Car(brand, price);
//3. 构造器引用 类名::new
createCar = Car::new;
//对象打印
System.out.println(createCar.create("宝马", 100000));
}
}
//接口功能: 完成Car对象的创建
interface CreateCar {
Car create(String brand, double price);
}
class Car {
private String brand;
private double price;
public Car(String brand, double price) {
this.brand = brand;
this.price = price;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", price=" + price +
'}';
}
}
(4)常见算法
-
冒泡排序 相邻的两个元素进行比较,小的放左边大的放右边,完成升序排列
-
实现步骤 确定总共需要做几轮: 数组长度-1 每轮比较几次: 轮数从0计数的话, 就是数组长度-1-当前轮数 比较规则: 相邻两个元素比较,大的放在右边
public class Demo1 {
public static void main(String[] args) {
int[] arr = {5, 2, 3, 1,10, 8, 9, 7, 6};
bubbleSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void bubbleSort(int[] arr) {
// 控制轮数:确定总共需要做几轮: 数组长度-1
for (int i = 0; i < arr.length-1 ; i++) {
// 每轮比较几次: 轮数从0计数的话, 就是数组长度-1-当前轮数
for (int j = 0; j < arr.length - 1 - i; j++) {
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
}
-
选择排序 每轮选择当前位置,开始找后面的最小值,与当前位置交换
-
关键点分析 确定总共需要做几轮: 数组长度-1 每次的基准位:轮数从0计数的话, 就是基准位索引敲好就是轮数 比较规则: 以每次的第一个为基准做比较,谁小谁来基准位
public class Demo2 {
public static void main(String[] args) {
int[] arr = {5, 2, 3, 1};
selectionSort(arr);
System.out.println(Arrays.toString(arr));
}
private static void selectionSort(int[] arr) {
// 控制轮数:确定总共需要做几轮: 数组长度-1
for (int i = 0; i < arr.length-1; i++) {
// 每次的基准位:轮数从0计数的话, 就是基准位索引恰好就是轮数(i+1)
for (int j = i+1; j < arr.length; j++) {
if(arr[i] > arr[j]){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
}
-
二分查找/折半查找 前提是数组有序 特点是每一次查找完成,会舍去一半元素
-
思路分析 1、定义两个指针,指向数组第一个和最后一个索引位置 2、循环查找,min小于等max则继续(三个指针可能重叠的) 3、每次循环进来,重新计算中间指针 4、判断情况1:如果mid指向的元素就是num,则返回mid 5、判断情况2:如果要查找的元素,在左半边,舍弃max重新计算 6、判断情况3:如果要查找的元素,在右半边,舍弃min重新计算 7、循环结束没有找到,则代表不存在,返回-1
public class Demo1 {
public static void main(String[] args) {
int[] arr = {10, 23, 39, 45, 59, 166, 728, 810, 999};
System.out.println("索引位置为:" + binarySearch(arr, 166));
System.out.println("索引位置为:" + binarySearch(arr, 200));
}
//二分查找
private static int binarySearch(int[] arr, int num) {
//1.设置返回索引
int index = -1;
//2.设置开始和结束索引
int min = 0;
int max = arr.length - 1;
//3.使用while循环,条件:左侧开始索引 <= 右侧结束索引
while (min<=max){
//4.计算中间索引
int mid = (min + max)/2;
//5.使用中间索引的数据和需要查询的num比较
//5.1 数据一致,返回索引位置
if(num == arr[mid]){
index = mid;
break;
}else if(num < arr[mid]){
//5.2 数据小于中间索引的数据,舍弃右侧数据,重新计算
max = mid - 1;
}else{
//5.3 数据大于中间索引的数据,舍弃左侧数据,重新计算
min = mid + 1;
}
}
//如果min>max,则代表没有找到,返回-1
//6.循环结束,返回索引位置
return index;
}
}
(5)正则表达式
-
用法 boolean 待校验字符串.matches("正则规则")
public class Demo1{
public static void main(String[] args) {
System.out.println(checkQQ(null));
System.out.println(checkQQ("251425876"));
System.out.println(checkQQ("2514a8d76"));
System.out.println("--------------------------------------------------");
System.out.println(checkQQWithRegex(null));
System.out.println(checkQQWithRegex("251425876"));
System.out.println(checkQQWithRegex("2514a8d76"));
}
//不用正则校验QQ号(qq至少是不是null,不是以0开头的,满足6-20之间的长度)
public static boolean checkQQ(String qq){
// 1、判断qq号码是否为null
if(qq == null || qq.startsWith("0") || qq.length() < 6 || qq.length() > 20){
return false;
}
// 2、判断qq号码中是否都是数字。
// qq = 2514ghd234
for (int i = 0; i < qq.length(); i++) {
// 根据索引提取当前位置处的字符。
char ch = qq.charAt(i);
// 判断ch记住的字符,如果不是数字,qq号码不合法。
if(ch < '0' || ch > '9'){
return false;
}
}
// 3、说明qq号码肯定是合法
return true;
}
//使用正则校验QQ号(qq至少是不是null,不是以0开头的,满足6-20之间的长度)
public static boolean checkQQWithRegex(String qq){
return qq != null && qq.matches("[1-9]\\d{5,19}");
}
}
-
语法 1、替换 替换后字符串 源字符串.replaceAll(正则规则, 待替换串) 2、分割 分割后数组 源字符串.split(正则规则)
public class Demo2 {
public static void main(String[] args) {
// 需求1:请把下面文字中的非中文字符替换成-
String s1 = "古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴";
System.out.println(s1.replaceAll("\\w+", "-"));
// 需求2:请把 下面文字中的人名获取出来
String s3 = "古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴";
String[] names = s3.split("\\w+");
System.out.println(Arrays.toString(names));
}
}
-
语法 1. 把正则表达式封装成一个Pattern对象 Pattern pattern = Pattern.compile(regex); 2. 通过pattern对象去获取查找内容的匹配器对象。 Matcher matcher = pattern.matcher(全文字符串); 3. 遍历查找 while (matcher.find()){ String rs = matcher.group(); }
public class Demo3 {
public static void main(String[] args) {
method1();
}
// 需求1:从以下内容中爬取出,手机,邮箱,座机、400电话等信息。
public static void method1(){
String data = " 来黑马程序员学习Java,\n" +
" 电话:1866668888,18699997777\n" +
" 或者联系邮箱:boniu@itcast.cn,\n" +
" 座机电话:01036517895,010-98951256\n" +
" 邮箱:bozai@itcast.cn,\n" +
" 邮箱:dlei0009@163.com,\n" +
" 热线电话:400-618-9090 ,400-618-4000,4006184000,4006189090";
// 1、定义爬取规则
String regex = "(1[3-9]\\d{9})|(0\\d{2,7}-?[1-9]\\d{4,19})|(\\w{2,}@\\w{2,20}(\\.\\w{2,10}){1,2})"
+ "|(400-?\\d{3,7}-?\\d{3,7})";
// 2、把正则表达式封装成一个Pattern对象
Pattern pattern = Pattern.compile(regex);
// 3、通过pattern对象去获取查找内容的匹配器对象。
Matcher matcher = pattern.matcher(data);
// 4、定义一个循环开始爬取信息
while (matcher.find()){
String rs = matcher.group(); // 获取到了找到的内容了。
System.out.println(rs);
}
}
}
public class Demo4 {
public static void main(String[] args) {
// 1、字符类(只能匹配单个字符)
//[abc]只能匹配a、b、c
System.out.println("a".matches("[abc]")); //true
System.out.println("e".matches("[abcd]")); //false
//[^abc] 不能是abc
System.out.println("d".matches("[^abc]")); //true
System.out.println("a".matches("[^abc]")); //false
//[a-zA-Z] 只能是a-z A-Z的字符
System.out.println("b".matches("[a-zA-Z]")); //true
System.out.println("2".matches("[a-zA-Z]")); //false
//[a-z&&[^bc]] a到z,除了b和c
System.out.println("k".matches("[a-z&&[^bc]]")); //true
System.out.println("b".matches("[a-z&&[^bc]]")); //false
//[a-zA-Z0-9] 任意数字和字母
System.out.println("b".matches("[a-zA-Z0-9]")); //true
System.out.println("ab".matches("[a-zA-Z0-9]")); //false
System.out.println("====================================");
// \转义
System.out.println("\"");
// 2、预定义字符(只能匹配单个字符)
//.可以匹配任意字符
System.out.println("徐".matches(".")); //true
System.out.println("徐徐".matches(".")); //false
//\d: 0-9
System.out.println("3".matches("\\d")); //true
System.out.println("a".matches("\\d")); //false
// \s: 代表一个空白字符
System.out.println(" ".matches("\\s")); //true
System.out.println("a".matches("\s")); //false
// \S: 代表一个非空白字符
System.out.println("a".matches("\\S")); //true
System.out.println(" ".matches("\\S")); //false
// \w: [a-zA-Z_0-9]
System.out.println("a".matches("\\w")); //true
System.out.println("_".matches("\\w")); //true
System.out.println("徐".matches("\\w")); //false
// [^\w]不能是a-zA-Z_0-9
System.out.println("徐".matches("\\W")); //true
System.out.println("a".matches("\\W")); //false
System.out.println("=================================");
// 3、数量词: ? * + {n} {n, } {n, m}
// ? 代表0次或1次
System.out.println("a".matches("\\w?")); //true
System.out.println("".matches("\\w?")); //true
System.out.println("abc".matches("\\w?")); //false
// * 代表0次或多次
System.out.println("abc12".matches("\\w*")); //true
System.out.println("".matches("\\w*")); //true
System.out.println("abc12张".matches("\\w*")); //false
// + 代表1次或多次
System.out.println("abc12".matches("\\w+")); //true
System.out.println("".matches("\\w+")); //false
System.out.println("abc12张".matches("\\w+")); //false
// {3} 代表要正好是n次
System.out.println("a3c".matches("\\w{3}")); //true
System.out.println("abcd".matches("\\w{3}")); //false
// {3,} 代表是>=3次
System.out.println("abcd".matches("\\w{3,}")); //true
System.out.println("ab".matches("\\w{3,}")); //false
System.out.println("abcde徐".matches("\\w{3,}")); //false
// {3, 9} 代表是 大于等于3次,小于等于9次
System.out.println("abc232d".matches("\\w{3,9}")); //true
}
}