正则表达式:
就是一些特定的字符串组成,代表的就是一个规则。在用作校验数据格式是否可发,更简单,更便捷。
书写规则:
String提供了一个匹配正则表达式的方法
public boolean matches(String regex)判断字符串是否匹配正则表达式,匹配返回true,不匹配返回false。
案例初体验:
检验一个qq号码是否符合格式
public class RegexDemo1 {
public static void main(String[] args) {
System.out.println(checkQQ("251425789"));
System.out.println(checkQQ("051425789"));
System.out.println(checkQQ("2514ab2579"));
System.out.println(checkQQ("2514"));
System.out.println(checkQQ(null));
}
/**
* 判断传入的qq号码的是否是合格的
* @param number
* @return
*/
private static boolean checkQQ(String number) {
if (number == null || number.startsWith("0") || number.length() < 6 || number.length() > 20){
return false;
}
for (int i = 0; i < number.length(); i++) {
char c = number.charAt(i);
if (c < '0' || c > '9'){
return false;
}
}
return true;
}
}
上面繁琐的代码,就是为了验证传入的QQ号码是否符合格式,我们可以用正则表达式进行改进。
public class RegexDemo1 {
public static void main(String[] args) {
System.out.println(checkQQ2("251425789"));
System.out.println(checkQQ2("051425789"));
System.out.println(checkQQ2("2514ab2579"));
System.out.println(checkQQ2("2514"));
System.out.println(checkQQ2(null));
}
public static Boolean checkQQ2(String str){
return str != null && str.matches("[1-9]\\d{5,19}");
}
}
应用案例:
检验用户输入的电话号码是否符合格式:
检查输入的手机号是否符合格式 13548494739 023-4343 012213131
public class CheckPhone {
public static void main(String[] args) {
checkPhone();
}
/**
* 检查输入的手机号是否符合格式
* 13548494739
*023-4343
*012213131
*/
public static void checkPhone(){
while (true) {
System.out.println("请输入你要注册的手机号:");
Scanner sc= new Scanner(System.in);
String phone = sc.next();
if (phone != null && phone.matches("(1[3-9]\\d{9})|(0[1-9]\\d{1,9}-?\\d{2,10})")){
System.out.println("注册成功");
break;
}else {
System.out.println("注册失败,格式不正确");
}
}
}
}
检验email格式是否符合要求:
* 检验输入的邮箱是否符合格式 12121212@qq.com dsds@163.com sundaoen@qq.com.cn
public class EmailCheck {
public static void main(String[] args) {
checkEmail();
}
/**
* 检验输入的邮箱是否符合格式
* 12121212@qq.com
* dsds@163.com
* sundaoen@qq.com.cn
*/
public static void checkEmail(){
Scanner sc = new Scanner(System.in);
while (true){
System.out.println("请输入你要添加的邮箱:");
String email = sc.next();
if (email.matches("\\w{2,25}@\\w{2,10}(\\.\\w{2,10}){1,2}")){
System.out.println("添加成功");
break;
}else {
System.out.println("添加失败,你输入的格式有误");
}
}
}
}
使用正则表达式查找文本中的内容:
public class TextRegexDemo {
public static void main(String[] args) {
String data = "来学校进行学习Java,\n" +
"电话:18512516758,18512508907\n" +
"或者联系邮箱: boniu@itcast.cn\n" +
"座机电话:01036517895,010-98951256\n" +
"邮箱:bozai@itjava.cn,\n" +
"邮箱2:dlei0009@163.com,\n" +
"热线电话:400-618-9090 ,400-618-4000,\n" +
"4006184000,4006189090\n";
// 创建一个匹配规则对象,封装正则表达式
String regex = "(1[3-9]\\d{9})|((0[1-9]\\d{1,4})-?[1-9]\\d{4,9})|(\\w{2,30}@\\w{2,20}(\\.\\w{2,10}){1,2})" +
"|(400-?[1-9]\\d{2,5}-?[1-9]\\d{2,5})";
Pattern pattern = Pattern.compile(regex);
//把内容和爬取规则建立联系,得到一个匹配对象
Matcher matcher = pattern.matcher(data);
//开始使用匹配器对象,爬取内容
while (matcher.find()){
System.out.println(matcher.group());
}
}
}
根据上面的需求,只需要把每个邮箱中的用户名爬取出来。
public class TextRegexDemo2 {
public static void main(String[] args) {
String data = "来学校进行学习Java,\n" +
"电话:18512516758,18512508907\n" +
"或者联系邮箱: boniu@itcast.cn\n" +
"座机电话:01036517895,010-98951256\n" +
"邮箱:bozai@itjava.cn,\n" +
"邮箱2:dlei0009@163.com,\n" +
"热线电话:400-618-9090 ,400-618-4000,\n" +
"4006184000,4006189090\n";
// 1、()是分组的意思,可以看出@前面一对小括号代表第一组,@后面的一对小括号,代表第二组
String regex = "(\\w{2,30})@(\\w{2,20})(\\.\\w{2,10}){1,2}";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(data);
while (matcher.find()){
System.out.println(matcher.group(1)); //提取正则表达式规则匹配的第一对小括号里面的内容
}
}
//boniu
//bozai
//asei0009
}
根据下面的信息,爬取所有进入系统的用户名
public class RegexDemo4 {
public static void main(String[] args) {
String data = "欢迎张狗蛋光临本系统!他删库并跑路欢迎李二狗子光临本系统!\" +\n" +
" \" 欢迎马六子光临本系统!它浏览了很多好看的照片!欢迎夏洛光临本系统!他在六点钟送出了一个嘉年华!";
String regex = "欢迎(.+?)光临";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(data);
while (matcher.find()){
//把爬到的信息提取出来
String group = matcher.group(1);//爬取内容中的第一组
System.out.println(group);
}
}
}
使用正则表达式替换和分割内容:
public String[] split(String regex) 按照正则表达式匹配的内容进行分割字符串,反回一个字符串数组。
- public String replaceAll(String regex,String newStr) 按照正则表达式匹配的内容进行替换
案例一:
// 需求1:请把 古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴,中间的非中文字符替换成 “-”
public class RegexDemo5 {
public static void main(String[] args) {
// 需求1:请把 古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴,中间的非中文字符替换成 “-”
String s1 = "古力娜扎ai8888迪丽热巴99fafas9aa5566马尔扎哈fbbADFFfsfs42425卡尔扎巴";
String result = s1.replaceAll("\\w+", "-");
System.out.println(result);
}
}
案例二
// 某语音系统,收到一个口吃的人说的“我我我喜欢编编编编编编编编编编编编程程程!”,需要优化成“我喜欢编程!”。
String s2 = "我我我喜喜欢编编编程程";
String result2 = s2.replaceAll("(.)\\1+", "$1");
System.out.println(result2);
案例三:
请把 古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴,中的人名获取出来。
String s3 = "古力娜扎ai8888迪丽热巴99fafas9aa5566马尔扎哈fbbADFFfsfs42425卡尔扎巴";
String[] name = s3.split("\\w+");
System.out.println(Arrays.toString(name));
效果:
java中的异常:
认识异常:
异常就是代表程序出现问题。
1,编译错误
2,运行时错误
3,逻辑错误
异常的结构:
所有异常类都有一个共同的祖先 Throwable(可抛出)
Throwable:有两个重要的子类,Exception(异常)和Error(错误)。异常和错误的区别是:异常能被程序本身可以处理,错误是无法处理。
Error(错误)
是程序本身可以处理的错误,表示运行应用程序中较为严重的错误。
Exception(异常)
是程序本身可以处理的异常。Exception 类有一个重要的子类 RuntimeException。
exception异常的分类:
它分为编译时异常和运行时异常
- 运行时异常:RuntimeException及其子类,编译阶段不会出现错误提醒,运行时出现的异常(如:数组索引越界异常)
- 编译时异常:编译阶段就会出现错误提醒的。(如:日期解析异常)
public class ExceptionDemo1 {
public static void main(String[] args) throws ParseException {
//运行时异常 RunTimeException
int[] arr = {12,23,43};
//System.out.println(arr[3]); //出现索引下标越界异常 ArrayIndexOutOfBoundsException
String name = null;
// System.out.println(name.toString());
// System.out.println(name.length()); //空指针异常 NullPointerException
/**
* 编译时异常,用来提醒我们这个代码很容易出现错误
*/
String str = "2023-11-12 15:09:12";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse(str); //这里就会出现编译时异常
System.out.println(date);
}
}
public class ExceptionDemo2 {
public static void main(String[] args) {
System.out.println("开始");
// divide(6,2);
try {
divide(10,0);
System.out.println("代码成功运行");
} catch (Exception e) {
System.out.println("系统出现了异常:"+e);
}
System.out.println("结束");
}
public static void divide(int a,int b){
if (b == 0){
throw new RuntimeException("b(除数不能为 0)");
}
System.out.println(a / b);
}
}
public class ExceptionDemo3 {
public static void main(String[] args) {
while (true) {
try {
System.out.println("商品定价是:"+getPrice());
break;
} catch (Exception e) {
System.out.println("你输入的价格有问题,请重新输入");
}
}
}
public static double getPrice(){
System.out.println("请输入你的商品定价:");
Scanner sc = new Scanner(System.in);
double price = sc.nextDouble();
return price;
}
}
final和finally和finallize的区别:
final为关键字
finalize()为方法
finally()为区块标记,用于try语句中
作用:
1,final 用于标识常量的关键字,final 标识的关键字存储在常量池中
2,finalize()方法在Object中进行了定义,用于在对象“消失”时,由JVM进行调用用于对对象 进行垃圾回收,类似于C++中的析构函数。
3,finally{}用于标识代码块,与try{ }进行配合,不论try中的代码执行完或没有执行完(这里指有异常),该代码块之中的程序必定会进行。
自定义异常:
自定义编译时异常:
- 继承Exception
- 重写父类构造器
首先我们先写一个SdeAgeException自定义的异常类,然后在写一个SdeAgeExceptionTest的测试类
//继承Exception类,重写它的构造方法
public class SdeAgeException extends Exception{
public SdeAgeException() {
super();
}
public SdeAgeException(String message) {
super(message);
}
}
测试类:
public class SdeAgeExceptionTest {
public static void main(String[] args) throws SdeAgeException {
System.out.println("开始。。。");
addAge(150);
System.out.println("结束。。。");
}
public static void addAge(int age) throws SdeAgeException {
if (age <=0 || age >= 150){
//可以发现 这一行出现了很明显的报错提示,那我们就抛出异常,这是编译时异常。
throw new SdeAgeException("age must be 1 -150 your age is"+age);
}else {
System.out.println("年龄添加成功");
}
}
}
效果图:
自定义运行时异常:
- 继承RuntimeException
- 实现父类的构造器
我们先定义一个SdeAgeRunTimeException类,然后在创建一个SdeAgeRunTimeExceptionTest的测试类。
public class SdeAgeRunTimeException extends RuntimeException{
public SdeAgeRunTimeException() {
super();
}
public SdeAgeRunTimeException(String message) {
super(message);
}
}
Test测试类:
public class SdeAgeRunTimeExceptionTest {
public static void main(String[] args) {
System.out.println("开始。。。");
addAge(157);
System.out.println("结束。。。");
}
public static void addAge(int age){
if (age <= 0 || age >= 150){
throw new SdeAgeRunTimeException("age must be 1 -150 your age is"+age);
}else {
System.out.println("年龄添加成功");
}
}
}
效果:
java中异常处理的机制:
捕获异常,抛出异常。
抛出异常:throw/throws
throw方法内部抛出异常,一般和try-catch一起使用
throws 方法后抛出
注意:
throw和throws都会把异常问题抛给主程序
捕获异常——try-catch-finally
语法:
try{
//可能出现错误的代码块
}catch(){ //捕获可能出现的异常
//代码块
}finally{
//注定要运行的出口
}
public class ExceptionDemo4 {
public static void main(String[] args) {
try {
testA();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
public static void testA() throws FileNotFoundException, ParseException {
testB();
InputStream is = new FileInputStream("D://dog.png");
}
private static void testB() throws ParseException {
String s = "2023-11-12 11:45:19";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(s);
System.out.println(d);
}
}
我们会发现,通过throw抛出异常,底层的异常抛出给外层,最外层中捕获处理。我们可以看出,主调方法的try-catch中出现了太多的catch,要是太多我们肯定就记不住了。不如直接写成Exception
try {
testA();
} catch (Exception e) {
e.printStackTrace();
}
java中的泛型:
认识泛型:
- 定义类,接口,方法时,同时声明了一个或者多个类型变量:如(<E>)称为泛型类,泛型接口,泛型方法。它们统称为泛型。
- 作用:泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力,这样可以避免强制类型转换,以及可能出现的异常。
泛型的本质:把具体的数据类型作为参数传递给类型变量。
泛型类:
修饰符 class 类名(类型变量,类型变量){
}
public class
ArrayList<E>{}
注意:泛型变量建议使用大写的英文字母,常用的有:E T K V
public class GenericDemo1 {
public static void main(String[] args) {
ArrayList list = new ArrayList(); //没有添加泛型,可以传递任意类型的数据
list.add("daoen1");
list.add(12);
list.add(true);
list.add('A');
System.out.println(list);
System.out.println("---------------");
ArrayList<String> list1 = new ArrayList<>(); //泛型是 String,只能接收String类型的数据
list1.add("sundaoen");
list1.add("javaproject");
list1.add("html+css");
for (int i = 0; i < list1.size(); i++) {
String s = list1.get(i);
System.out.println(s);
}
}
}
泛型接口:
修饰符 interface 接口名 (类型变量,类型变量...)
public interface Dog<E>{}
我们先自定义一个泛型接口:Data
public interface Data<E> {
void add(E e);
boolean delete(E e);
boolean update(E e);
E getById(int id);
}
定义Student类:
public class Student {
}
定义Teacher类:
public class Teacher{
}
定义学生StudentDao类:实现泛型接口Data
public class StudentDao implements Data<Student>{
@Override
public void add(Student student) {
}
@Override
public boolean delete(Student student) {
return false;
}
@Override
public boolean update(Student student) {
return false;
}
@Override
public Student getById(int id) {
return null;
}
}
定义TeacherDao实现Data泛型接口类:
public class TeacherDao implements Data<Teacher>{
@Override
public void add(Teacher teacher) {
}
@Override
public boolean delete(Teacher teacher) {
return false;
}
@Override
public boolean update(Teacher teacher) {
return false;
}
@Override
public Teacher getById(int id) {
return null;
}
}
定义测试类:
public class Test {
public static void main(String[] args) {
Student student = new Student();
StudentDao stuDao = new StudentDao();
stuDao.add(student);
stuDao.delete(student);
stuDao.getById(1);
stuDao.update(student);
System.out.println("-------------------------");
Teacher teacher = new Teacher();
TeacherDao tDao = new TeacherDao();
tDao.add(teacher);
tDao.delete(teacher);
tDao.getById(1);
tDao.update(teacher);
}
}
泛型方法:
修饰符 (类型变量,类型变量...) 返回值类型 方法名(形参列表){}
public static <E> void test(E e){}
public class GenericDemo1 {
public static void main(String[] args) {
Integer[] age = {13,23,54,65,43};
printArr(age);
String[] names = {"三张","发的","时尚大方"};
printArr(names);
Integer max = getMax(age);
String max1 = getMax(names);
}
public static <E> void printArr(E[] arr){
}
public static <E> E getMax(E[] arr){
return null;
}
}
通配符:
就是 "?" ,可以在使用泛型的时候代表一切类型, E T K V 是在定义泛型的时候使用
泛型的上下限:
泛型的上限: ?extend 一个父类 ?能接收的必须是这个父类(比如Car)或者其子类
泛型的下限:?super 一个父类 ?能接收的必须是比如(Car)或者其父类
public class GenericDemo2 {
public static void main(String[] args) {
// ArrayList<Cat> cats = new ArrayList<Cat>();
ArrayList<Cat> cats = new ArrayList<>(); //因为左边已经写好了,所以右边的泛型不需要在指定类型了。
cats.add(new Cat());
cats.add(new Cat());
cats.add(new Cat());
eat(cats);
System.out.println("----------------------");
ArrayList<Dog> dogs = new ArrayList<>();
dogs.add(new Dog());
dogs.add(new Dog());
dogs.add(new Dog());
eat(dogs);
}
// Java提供了泛型上下限,约束?的具体类型。
// ? extends Animal : 上限: ? 必须是Animal的子类,顶多是Animal
// ? super Animal : 下限: ? 必须是Animal的父类,至少是Animal
public static void eat(ArrayList<? extends Animal> animals ){
}
}
class Animal{}
class Dog extends Animal{}
class Cat extends Animal{}
泛型的擦除问题和注意事项:
- 泛型是工作在编译阶段的,一旦程序编译成class文件,class文件中就不存在泛型了,这就是泛型擦除。 泛型不能直接支持基本数据类型,只能支持对象类型(引用数据类型)。