赵大超的学习周志(四)

本周是Java基础学习的第四周,主要是对异常进行了学习,最主要的是对各种常用类的学习,最后还学习了对正则表达式的使用。异常部分主要包括系统异常和自定义异常;常用类的学习包括了BigDecimal与DecimalFormat、Objects类、Random类、File类、Date类、DateFormat & SimpleDateFormat、Calendar类等;正则表达式则学习了其语法和对Pattern&Matcher类的使用。对于本周的学习我觉得难度不算大但又非常难以记忆,因为通过查阅API文档可以对各种常用类的各种方法进行了解并使用,但自己使用时又记不住各个类各个方法的用法,甚至想不起实现某项功能时需要使用的方法的方法名,可能还需要在日常应用中多去使用才能熟能生巧。现将本周学习的各种知识点罗列如下,方便自己复习查看。

异常捕获

异常的捕获即,将有可能出现异常的代码片段使用try语句块进行包裹,然后使用catch语句块将有可能产生的异常类型进行捕获,并作出处理。

异常捕获常见的关键字:

  • try
  • catch
  • finally

语法结构:

try{//有可能出现异常的代码片段
}catch(异常类型 变量名){//处理异常
}finally{//不论是否出现异常,始终执行
}

程序执行到try语句块,在执行期间如果出现了对应catch的异常类型,则直接进入catch语句块,如果catch语句块中没有合适的异常解决方案,则由JVM进行统一处理(打印异常的堆栈信息)。

关于异常的常见面试题

  1. 请你说出 final、finalize和finally的区别?
    答:final是一个关键字用于修饰类,属性,方法;
    finalize是Object类中提供的一个方法,用于在jvm对对象清理时,对于当前对象执行一些最终的处理工作的;
    finally是异常中的语句块
  2. java中是否会存在内存溢出的问题?
    答:理论上java不会存在内存泄漏问题,因为jvm提供了GC(垃圾回收:garbage collection)机制,会在适当的时候自动回收内存空间,不需要由程序员手动处理;但是如果使用第三方资源(比如:打开一个文件,打开了网络通道,打开数据库连接等)并且未及时的清理以及回收,将会导致内存泄漏。
  3. 异常处理中finally和return的结合使用?
    答:如果try语句块中有使用return,并且try语句块中没有任何异常时,程序首先会执行finally然后再执行return;但是对于基本类型的数据,finally的赋值是不会生效的,但是finally中操作引用类型的属性可以生效
//程序正常执行,返回 20;finally中的赋值无效
public static int m2() {int i = 10;try {i = 20;return i;      }catch(Exception e){e.printStackTrace();}finally {i = 30;System.out.println("finally");}return i;
}//程序正常执行,返回对象中的name属性值被修改为“李四”;finally中的赋值生效
public static User m3() {User u = new User();try {u.name = "张三";return u;}catch(Exception e) {e.printStackTrace();} finally {u.name = "李四";}return u;
}

BigDecimal

java.math.BigDecimal类从java.math.Number类继承而来,用于表示精度较高的数值类型的封装类型,一般用于精度要求较高的程序中,比如银行账户的金额属性。

常见方法:

  • add(BigDecimal b):与另一个BigDecimal执行相加运算
  • subtract(BigDecimal b):与另一个BigDecimal执行相减运算
  • multiply(BigDecimal b):与另一个BigDecimal执行相乘运算
  • divide(BigDecimal b):与另一个BigDecimal执行相除运算
double d1 = 0.1;
double d2 = 0.2;
//      System.out.println(d1 + d2);
//在涉及到一些敏感的浮点数运算时,不适合直接使用float和double,精度丢失BigDecimal b1 = new BigDecimal("0.1");
BigDecimal b2 = new BigDecimal("0.2");//相加 a + b =>  a.add(b)
System.out.println(b1.add(b2));
System.out.println(b1.add(b2,MathContext.DECIMAL128)); //相减 a - b => a.subtract(b)
System.out.println(b1.subtract(b2));//相乘 a * b => a.multiply(b)
System.out.println(b1.multiply(b2));//相除 a / b => a.divide(b)
System.out.println(b1.divide(b2));

对于相除运算的使用:

BigDecimal d1 = new BigDecimal("10");
BigDecimal d2 = new BigDecimal("3");
//当两个数值相除为无限循环数时会出现算术异常
//向上取整
System.out.println(d1.divide(d2,RoundingMode.CEILING));
//向下取整
System.out.println(d1.divide(d2,RoundingMode.FLOOR));//向上保留指定位小数点
System.out.println(d1.divide(d2, 2, BigDecimal.ROUND_CEILING));
//向下保留指定位小数点
System.out.println(d1.divide(d2, 2, BigDecimal.ROUND_FLOOR));

NumberFormat & DecimalFormat

java.text.NumberFormatjava.text.DecimalFormat是用于进行数值格式化的类,可以对数值的显示位数进行格式化处理,以及对浮点数进行金额或者百分比的格式表现;DecimalFormat是NumberFormat的子类。

java.text.NumberFormat是一个抽象类,内部提供了几个静态方法用于直接获取NumberFormat对象,而这些静态方法的实现通过java.text.DecimalFormat实现。

NumberFormat常见方法:

  • format(double d):将一个double值按指定的格式转换为String
  • parse(String s):将一个String类型的数值解析为double类型
double d = 150500.491987;
//获取用于进行货币格式化(本地环境)的数值格式化对象
NumberFormat fmt = NumberFormat.getCurrencyInstance();
//将浮点数转换为字符串类型的固定格式
String s = fmt.format(d);
System.out.println(s);//¥150,500.49//获取整数类型的格式化对象
fmt = NumberFormat.getIntegerInstance();
System.out.println(fmt.format(d));//150,500//获取标准的数值类型格式化对象(对于小数点最大保留后三位)
fmt = NumberFormat.getNumberInstance();
System.out.println(fmt.format(d));//150,500.492//获取进行百分比格式化的对象
fmt = NumberFormat.getPercentInstance();
System.out.println(fmt.format(0.456789));//46%

由于NumberFormat提供的方法可能无法满足一些个性化的格式需求,比如需要将double值转换为百分比,并保留小数点后两位,NumberFormat中提供的格式化方法getPersentInstence()只能保留整数位;因此,我们需要能够自定格式的工具,所以java中提供的java.text.DecimalFormat就能够满足需求了:

//创建一个数值格式化对象
DecimalFormat fmt = new DecimalFormat("##.##%");
System.out.println(fmt.format(0.456789)); // 45.68%fmt = new DecimalFormat("\u00A4##,###,###.#");
System.out.println(fmt.format(5423423467890.345)); //¥5,423,423,467,890.3//NumberFormat&DecimalFormat不仅能够将double值按指定的格式格式化为String,
//同时,也能将String类型表示的数字解析为需要的数值类型
String s = "50.67%";
//将以上字符串转换为double值   0.5067
fmt = new DecimalFormat("##.##%");
Number num = fmt.parse(s);
System.out.println(num.doubleValue());

Objects类

Object类是所有java类的顶层父类(祖宗类),但是Objects是从Java7开始新增的一个对于java对象进行空指针安全操作的工具类

  • Objects类是一个工具类
  • Objects对外不提供构造器,因此无法创建对象
  • Objects类中的所有方法都是static
  • 提供的是对于对象的空指针安全操作的方法
User u1 = new User(1, "softeem", "123456");
User u2 = null;//      if(u2 != null) {
//          System.out.println(u2.equals(u1));
//      }
//空指针安全的对象比较
System.out.println(Objects.equals(u1, u2));
//空指针安全的toString
System.out.println(Objects.toString(u2)); // 对象若为null则输出“null”字符串
System.out.println(Objects.toString(u2,"0")); //对象若为null则输出“0”//空指针安全的hashCode
System.out.println(Objects.hashCode(u2));
//为空判断
System.out.println(Objects.isNull(u2));
//不为空判断
System.out.println(Objects.nonNull(u2));
//检查对象不为空,若为空则抛出NullPointerException
System.out.println(Objects.requireNonNull(u2));

Random类

Math类中提供了一个random()的方法,用于随机一个从0.0~1.0之间的浮点数,当实际需求有个性化的要求时,只能通过计算获取其他类型的随机数,实际操作相对比较麻烦;因此,Java中还提供了另一个专门用于生成各种需求的随机数类型,比如,随机整数,随机浮点数,随机布尔值。

构造器:

  • Random()

常见方法:

  • nextBoolean():随机一个布尔值
  • nextDouble():随机一个0.0~1.0之间的double值
  • nextInt():随机一个int范围内的整数值
  • nextInt(int bounds):随机一个从0~bounds-1位的整数值
public class RandomDemo {private static final class RandomGeneratorHolder{static final Random randomNumberGenerator = new Random();}private static final String SOURCE = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机指定长度位验证码public static String genCode(int count) {String code = "";for(int i = 0;i < count;i++) {int index = RandomGeneratorHolder.randomNumberGenerator.nextInt(SOURCE.length());code += SOURCE.charAt(index);}return code;}public static void main(String[] args) {Random r = new Random();//随机布尔值boolean f = r.nextBoolean();System.out.println(f);//随机一个从0.0~1.0之间的浮点数double d = r.nextDouble();System.out.println(d);int i = r.nextInt();System.out.println(i);//随机一个5以内的整数i = r.nextInt(5);System.out.println(i);//随机一个5(含)~10(含)之间的整数i = r.nextInt(6) + 5;System.out.println(i);//随机生成指定长度的验证码,包含0-9A-Za-z之间的字符String code = genCode(6);System.out.println(code);}
}

File类

File类是来自于java.io包中的一个用于处理本机操作系统中的文件,文件可以是目录也可以是一个标准文件;File类是用于在Java中实现跟本机文件系统进行关联的操作类。其中包含一些常见的文件操作:创建文件/目录,查看文件的状态,删除文件等。

常见属性:

常量 解释
pathSeparator 获取与本机系统相关的路径分隔符(windows是";"符号,Linux是”:“符号)
separator 获取与本机系统相关的目录分隔符(windows是”\“,Linux是”/“)

构造器:

File(File parent, String child) 使用父目录所表示的File对象,结合子文件名构建新的File对象
File(String pathname) 根据提供的文件路径构建一个File对象
File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例。
File(URI uri) 通过将给定的 file: URI转换为抽象路径名来创建新的 File实例。

常用方法:

  • createNewFile() 创建新文件(标准文件)
  • exists() 判断File对象是否存在
  • delete() 删除File对象所表示的文件或者目录(空目录)
  • deleteOnExit() 当JVM结束时删除
  • getName() 获取File对象所表示的文件名称
  • getParent() 获取File所指的文件或者目录的父路径
  • isFile() 判断当前File所指的是否是标准文件
  • isDirectory() 判断当前File所指的是否是目录
  • isHidden() 判断当前File对象是否是隐藏目录
  • lastModified() 获取最后修改时间
  • length() 获取File所表示文件大小(目录为4096)
  • list() 获取File所表示目录下所有子文件的名称数组
  • listFiles() 获取File对象所表示目录下的所有子File数组
  • listFiles(FileFilter filter) 通过文件过滤器将File所表示目录中符合条件的File对象过滤出来
  • listRoots() 获取当前电脑可用的磁盘根
  • mkdir() 创建当前File所表示的目录(一级)
  • mkdirs() 创建当前File所表示的目录(多级)
  • renameTo(File file) 重命名文件

测试一:

public class FileDemo1 {public static void main(String[] args) throws IOException {//获取与本机系统相关的路径分割符System.out.println(File.pathSeparator); // windows是;     linux是://获取与本机系统相关的名称(目录)分割符System.out.println(File.separator); //windows是 \          linux是 /
//      System.out.println(File.separatorChar);//通过java程序操作本地文件,在java中就必须存在文件对象(逻辑)//根据提供的文件的绝对路径(abstract path)获取文件对象File file = new File("D:/music_db.sql");//根据提供的文件相对路径(relative path)获取文件对象File file2 = new File("test/a.txt");//输出File对象所表示文件的绝对路径System.out.println(file.getAbsolutePath());System.out.println(file2.getAbsolutePath());//输出File对象所有表示文件的相对路径System.out.println(file.getPath());System.out.println(file2.getPath());//判断文件的可用性:可执行,可读,可写System.out.println(file2.canExecute());System.out.println(file2.canRead());System.out.println(file2.canWrite());//判断文件是否存在System.out.println("文件(或目录)是否存在-->"+file2.exists());file2 = new File("test/com");//创建新文件(标准文件)前提:父目录必须存在,否则IO异常boolean b = file2.createNewFile();System.out.println("文件创建结果--->"+b);file2 = new File("D:\\带班资料\\2020\\j2009\\code\\part1-javabase\\lesson17\\test\\org\\softeem\\demo");//创建目录(创建一级目录)System.out.println("一级目录创建结果--->"+file2.mkdir());System.out.println("创建多级目录--->"+file2.mkdirs()); //      Random r = new Random();
//      for (int i = 0; i < 1000; i++) {//          File f3 = new File(file2, r.nextInt(10000)+""+i);
//          if(f3.mkdirs()) {//              System.out.println(f3.getAbsolutePath()+"创建成功!");
//          }
//      }}}

测试二:

public class FileDemo2 {public static void main(String[] args) throws IOException, InterruptedException {// 创建临时文件
//      File f = File.createTempFile("softeem", ".log",new File("test"));
//      System.out.println(f.getAbsolutePath());//      if(f.exists()) {//          立即删除文件
//          boolean b = f.delete();
//          System.out.println("删除结果:"+b);
//      }File f2 = new File("test/a.txt");// 删除目录的前提是目录下没有任何子文件或者子目录
//      System.out.println("删除目录-->"+f2.delete());
//      当jvm结束才删除
//      f2.deleteOnExit();//        System.out.println(5/0);// 休眠5秒
//      Thread.sleep(10000); // 返回当前文件所在磁盘的剩余空间(字节)long size = f2.getFreeSpace();System.out.println(size / (1024 * 1024 * 1024) + "GB");//获取当前文件所在磁盘的总空间大小size = f2.getTotalSpace();System.out.println(size / (1024 * 1024 * 1024) + "GB");//获取file对象所表示的文件名称System.out.println(f2.getName());//获取File对象所表示文件所在的父目录名称(String)System.out.println(f2.getParent());//获取File对象所表示文件所在的父目录File对象(File)System.out.println(f2.getParentFile());}}

文件过滤

File类中提供了几个用于列出指定目录下所有子文件的方法:

  • list()
  • listFiles()

以上两个方法不会对文件进行任何的限制和过滤,直接全部遍历,但是以上两个方法还提供了对应的重载方法

  • list(FilenameFilter filter)
  • listFiles(FileFilter filter)
  • listFiles(FilenameFilter filter)

过滤方式一:
以listFiles(FileFilter filter)为例,使用方法如下:

File f = new File("D:\\素材\\音乐\\music素材");//创建过滤器对象
FileFilter filter = new FileFilter() {//回调函数@Overridepublic boolean accept(File f) {return f.getName().endsWith(".mp3"); }
};
File[] files = f.listFiles(filter);for (File file : files) {System.out.println(file.getName());
}

以上程序执行之后会获取所有的mp3文件,实现原理如下:

以上程序的实现,使用了匿名内部类,回调机制

过滤方式二:

创建文件过滤器:

/***     文件过滤器* @author mrchai*/
public class MyFileFilter implements FileFilter {private String suffix;public MyFileFilter(String suffix) {this.suffix = suffix;}/***  实现过滤规则*/@Overridepublic boolean accept(File f) {   return f.getName().endsWith(suffix);}}

测试类:

public class FileDemo5 {public static void main(String[] args) {File f = new File("D:\\素材\\音乐\\music素材");//创建过滤器对象FileFilter filter = new MyFileFilter(".jpg");//使用过滤器进行文件过滤File[] files = f.listFiles(filter);for (File file : files) {System.out.println(file.getName());}}}

文件递归遍历
在对系统文件加遍历时往往会遇到一种情况:需要将一个目录下的所有子文件全部获取,但是该目录下可能还存在子目录,以及多个子目录嵌套的情况;而具体的嵌套层次是未知的,因此无法使用传统的循环语句进行遍历,此时,最好的方式可以通过递归实现遍历:

public class FileDemo6 {/***     读取指定目录中的所有子文件* @param dir 源目录*/public static void readDir(File dir) {//获取目录下所有的文件对象(数组)File[] files = dir.listFiles();//判断数组对象是否为nullif(Objects.nonNull(files)) {//遍历所有的File对象for(File file:files) {//判断当前File对象所表示的是否一个目录if(file.isDirectory()) {//如果是目录,则递归遍历readDir(file);}//输出文件(或者目录)名称System.out.println(file.getName());}}}public static void main(String[] args) {//源目录File dir = new File("D:\\java");//读取readDir(dir);}}

File补充方法

File f = new File("d:/username.txt");System.out.println("文件是否存在:" + f.exists());System.out.println("判断是否是隐藏文件:" + f.isHidden());System.out.println("文件大小(字节):" + f.length());// 从1970年01月01日 00:00:00 ~ 指定时间之间的毫秒数
System.out.println("文件的最后修改时间:" + f.lastModified());// 列出当前系统中可用的盘符
File[] files = File.listRoots();
for (File file : files) {System.out.println(file);
}f = new File("d:/新建文本文档.txt");
//文件重命名
boolean b = f.renameTo(new File("d:/a.txt"));
System.out.println("重命名结果:" + b);

日期处理类

Date类

java.util.Date是一个传统的java用于处理日期时间的类,由于版本更新,内部有很多构造器包括方法均已标记为过时,取而代之的是java.util.Calendar类。

常用构造器:

  • Date():获取当前系统时间所表示的日期对象
  • Date(long time):根据提供的时间毫秒数,构建一个日期对象(从1970年1月1日 00:00:00开始)
Date d = new Date();//      d = new Date(120,11,1);d = new Date(System.currentTimeMillis());
System.out.println(d);//获取十分钟之后的日期对象  1sec = 1000
d = new Date(System.currentTimeMillis() + 600000);
System.out.println(d);

常用方法:

  • after(Date d)
  • before(Date d)
  • compareTo(Date d)
  • getTime()
//判断当前日期对象是否是参数日期对象之后的日期
System.out.println(d1.after(d2));System.out.println(d1.before(d2));Date d3 = new Date();
System.out.println(d3.equals(d1));
//获取当前日期对象所表示的时间毫秒数
System.out.println(d3.getTime());
System.out.println(d1.getTime());//     System.out.println(d3.getYear());

日期格式化(DateFormat & SimpleDateFormat)

DateFormat类来自java.text包下的用于进行日期时间格式化处理的类,是一个抽象类,内部提供了一系列用于获取格式化对象的静态方法:

  • getDateInstance()
  • getTimeInstance()
  • getDateTimeInstance()
  • getInstance()

SimpleDateFormat
DateFormat中提供的静态方法可以用户获取各种丰富的格式化对象,但是针对一些需求DateFormat并不能完全满足,比如需要如下格式日期:

  • 20201120
  • 2020年11月20日 09时48分50秒
  • 10:11:35

通过观察DateFormat中getInstance()源码得知,内部使用了一个子类SimpleDateFormat实现,SimpleDateFormat可以通过定制化的匹配模式来匹配不同的日期时间输出格式:

实力参考:

使用方式:

Date d = new Date();//20201120
DateFormat fmt = new SimpleDateFormat("yyyyMMdd");
time = fmt.format(d);
System.out.println(time);//2020年11月20日 09时48分50秒
fmt = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒 SSS毫秒");
time = fmt.format(d);
System.out.println(time);//[10:05:55]
fmt = new SimpleDateFormat("[HH:mm:ss]");
System.out.println(fmt.format(d));/********将String类型的日期时间转换为Date类型对象********/
String dateTime = "1999/11/11 09:10:11";
fmt = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
//将字符串类型的时间根据指定的格式解析为Date对象
Date date = fmt.parse(dateTime);
System.out.println(date);

Calendar
从JDK1.1开始java.util.Date中的很多方法和构造器标记为过时,同时jdk新增了对应的替代方案:java.util.Calendar,是一个抽象类,有一个直接子类:java.util.GregorianCalendar对其继承,并且实现其中的抽象方法,常见的Calendar实例获取方式为直接使用内部提供的静态方法getInstance()。

具体使用如下:

//以当前系统时间为基础获取日历实例  +8
Calendar c = Calendar.getInstance();
System.out.println(c);

常见字段:

  • YEAR
  • MONTH
  • DAY_OF_MONTH
  • HOUR
  • MINITE
  • SECOND
  • DAY_OF_WEEK

常见方法:

  • get(int field)
  • set(int field,int value)
  • getActualMaximum(int field)

具体用法:

//以当前系统时间为基础获取日历实例  +8
Calendar c = Calendar.getInstance();
System.out.println(c);//设置日历到2019年11月20日?
//      c.set(2019, 10, 20);
//设置日历对象中指定字段的值
c.set(Calendar.YEAR, 2019);System.out.println("获取日历表示的年份:"+c.get(Calendar.YEAR));
System.out.println("获取日历表示的月份(月份从0开始):"+c.get(Calendar.MONTH));
System.out.println("获取日历表示的日期"+c.get(Calendar.DAY_OF_MONTH));
System.out.println("获取日历表示的小时"+c.get(Calendar.HOUR_OF_DAY));
System.out.println("获取日历表示的分钟"+c.get(Calendar.MINUTE));
System.out.println("获取日历表示的秒钟"+c.get(Calendar.SECOND));
System.out.println("获取日历表示的毫秒"+c.get(Calendar.MILLISECOND)); System.out.println("获取当前日历表示的日期是今年的第多少天:"+c.get(Calendar.DAY_OF_YEAR));System.out.println("获取日历所有表示的时间毫秒数"+c.getTimeInMillis());//设置月份为12月
c.set(Calendar.MONTH, 11);
//获取当前日期所表示字段的可能最大值
int maxDay = c.getActualMaximum(Calendar.DAY_OF_MONTH);
System.out.println(maxDay); //31int maxMonth = c.getActualMaximum(Calendar.MONTH);
System.out.println(maxMonth);//11  (0~11)
//获取小时(24小时制)的最大值
int maxHour = c.getActualMaximum(Calendar.HOUR_OF_DAY);
System.out.println(maxHour); //23   (0~23)
//获取小时(12小时制)的最大值
maxHour = c.getActualMaximum(Calendar.HOUR);
System.out.println(maxHour);//计算从你出生到现在一共生活了多少天?(生命倒计时)  1000 * 60 * 60 * 24
c.set(1999, 10, 11);
long start = c.getTimeInMillis();
long now = System.currentTimeMillis();long days = (now - start) / (1000 * 60 * 60 * 24);
System.out.println(days);//将日历的日期设置为1号(设置为这个月的第一天)
c.set(Calendar.DAY_OF_MONTH, 1);System.out.println(c.get(Calendar.DAY_OF_WEEK));GregorianCalendar gc = (GregorianCalendar)c;
//判断指定年份是否是闰年(该方法为GregorianCalendar特有,因此需要将Calendar强制转换)
boolean leapYear = gc.isLeapYear(2020);
System.out.println(leapYear);//将Calendar转换为java.util.Date
Date date = c.getTime();
System.out.println(date);

正则表达式

正则表达式( Regular expression)是一组由字母和符号组成的特殊文本, 它可以用来从文本中找出满足你想要的格式的句子。正则表达式最早源自于perl语言(脚本语言);正则表达式的功能十分强大,可以用于进行文本的匹配,检索,替换;常见于一些网络爬虫。

java中对于正则表达式的处理主要由一下三个类实现:

  • java.lang.String
  • java.util.regex.Pattern
  • java.util.regex.Macher

简单案例:

String a = "13567845635";
//判断两个字符串是否完全一致
System.out.println(a.equals("13567845634"));
//判断当前String对象是否匹配给定的正则表达式( 匹配手机号格式字符串)
System.out.println(a.matches("^1\\d{10}$"));

匹配元字符:

元字符 说明
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束
//.用于匹配出回车换行之外的其他任意单个字符(数字,字母,符号)
System.out.println("!".matches("."));  //true//匹配所有的数字,字母,不支持符号
System.out.println("a".matches("\\w")); //true//匹配除了数字,字母外的其他符号
System.out.println("\t".matches("\\W"));//true//匹配空格
System.out.println(" ".matches("\\s"));//true//匹配非空格
System.out.println(" ".matches("\\S"));//false//匹配数字
System.out.println("0".matches("\\d"));//true
//匹配非数字
System.out.println("a".matches("\\D"));//true//边界匹配,匹配是否以指定字符开头
System.out.println("abc".matches("\\babc")); //true
System.out.println("a".matches("^a")); //true//边界匹配,匹配是否以指定的字符结尾
System.out.println("d".matches("d$")); //false

匹配长度:

语法 说明
* 重复零次或更多次
+ 重复一次或更多次
重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
//匹配输入长度为4的数字要求必须以1开头System.out.println("1234".matches("^1\\d{3}"));//验证输入的是否是qq号  5-11位长度数字,不能以0开始
System.out.println("12334352324".matches("^[1-9]\\d{4,10}"));// \\w
System.out.println("a".matches("[0-9a-zA-Z]")); //匹配不能少于5位长度的数字
System.out.println("12387912".matches("\\d{5,}"));//匹配不能超过6位长度的数字
System.out.println("12346".matches("\\d{0,6}"));//匹配字母0个或多个
System.out.println("".matches("[a-zA-Z]*")); //匹配字母1个或多个
System.out.println("a".matches("[a-zA-Z]+"));//匹配字母0个或1个
System.out.println("ac".matches("[a-zA-Z]?"));

Pattern&Matcher

String content = "adfasdffdiu1353457839417812341023u901223423418712312317823sdfsd";
//手机号正则表达式
String regex = "1\\d{10}";
//编译正则表达式获取匹配模式对象
Pattern p = Pattern.compile(regex);
//对指定的输入内容进行匹配并且获取匹配器
Matcher m = p.matcher(content);
//直接匹配
//System.out.println(m.matches());
//搜索是否存在匹配的组
while(m.find()) {   //取出当前匹配到的组String s = m.group();System.out.println(s);
}

经典练习

最后是两个练习题主要考察java常用类中Random、BigDecimal以及ArrayList类综合使用能力,同时对面向对象(封装,继承,多态)技术进行实践能力考察。

微信红包(拼手气红包)

基于BigDecimal类实现微信红包算法的功能,比如设置红包总金额,然后设置需要生成的红包个数,为每个红包随机指定金额,最低不能低于0.01元,要求:

  1. 每个红包金额随机指定
  2. 每个红包金额不能低于0.01元
  3. 要求每个红包的金额之和恰好等于总金额
  4. 如果平均每个红包的金额不足0.01元时抛出一个RedPacketException,提示每个红包金额不能少于0.01元

红包类:

/***     红包类**/
public class RedPacket {/**红包ID*/private int id;/**红包金额*/private BigDecimal money;public RedPacket() {}public RedPacket(int id, BigDecimal money) {super();this.id = id;this.money = money;}public int getId() {return id;}public void setId(int id) {this.id = id;}public BigDecimal getMoney() {return money;}public void setMoney(BigDecimal money) {this.money = money;}@Overridepublic String toString() {return id+"号用户获得"+money+"元";}}

红包异常类:

/***     红包异常* */
public class RedpacketException extends Exception{public RedpacketException() {// TODO Auto-generated constructor stub}public RedpacketException(String msg) {super(msg);}
}

红包管理类:

public class RedPacketManage {/** 设置每个红包最小金额 */static final BigDecimal MIN = new BigDecimal("0.01");/** @double total 总金额* @int count 红包个数* @return 返回生成的所有红包金额集合*/public static ArrayList<RedPacket> genRedPacket(double total, int count) throws RedpacketException {// 声明临时变量用于存储所有随机的红包对象ArrayList<RedPacket> packets = new ArrayList<RedPacket>();// 计算每个红包分配最低金额一共需要多少钱double min = MIN.multiply(new BigDecimal(count)).setScale(2, BigDecimal.ROUND_HALF_EVEN).doubleValue();if (min > total) {// 红包金额不够分配时,抛出异常throw new RedpacketException("每个红包金额不能少于0.01元");} else if (min == total) {// 红包金额恰好每人只够分配0.01元,则平均分配for (int i = 0; i < count; i++) {// 创建红包对象RedPacket item = new RedPacket(i + 1, new BigDecimal("0.01"));// 将红包加入集合packets.add(item);}} else {// 当总金额大于每人最少金额之和时,随机分配// 将总金额包装为BigDecimalBigDecimal totalMoney = new BigDecimal(total);//声明临时变量统计当前分配的金额总数BigDecimal now = new BigDecimal(0);// 获取每个红包的比例double[] scale = randomScale(count);// 为前count-1个红包分配金额for (int i = 0; i < count - 1; i++) {// 获取当前比例红包需要分配的金额BigDecimal item = totalMoney.multiply(new BigDecimal(scale[i])).setScale(2, BigDecimal.ROUND_HALF_EVEN);packets.add(new RedPacket(i + 1, item));//累计已分配金额总数now = now.add(item);}// 剩余的金额给最后一个//获取剩余的金额BigDecimal last = totalMoney.subtract(now);packets.add(new RedPacket(count, last));}return packets;}/***     随机红包金额比例* @param count 红包的份数* @return 每份红包的比例数组*/private static double[] randomScale(int count) {// 临时数组存储所有红包的金额比例double[] scale = new double[count];Random r = new Random();double total = 0.0;for (int i = 0; i < count; i++) {// 为每一个元素设置一个1-100随机数scale[i] = r.nextInt(100) + 1;// 累计所有随机的数值total += scale[i];}// 循环计算每个红包的金额比例for (int i = 0; i < count; i++) {scale[i] = scale[i] / total;}return scale;}}

测试类:

    ArrayList<RedPacket> list = genRedPacket(5, 10);BigDecimal t = new BigDecimal(0);for (RedPacket rp : list) {System.out.println(rp);t= t.add(rp.getMoney());}System.out.println(t);
}

运行结果:

1号用户获得0.70元
2号用户获得0.13元
3号用户获得0.46元
4号用户获得0.50元
5号用户获得0.59元
6号用户获得0.92元
7号用户获得0.02元
8号用户获得0.11元
9号用户获得0.65元
10号用户获得0.92元
5.00

斗地主发牌

参考斗地主的游戏规则,完成一个发牌的功能(54张牌,考虑点数,花色;三名玩家,其中地主比其他玩家多3张牌)

牌类:

/*** 3-10 J Q K A 2 Queen King 牌类* */
public class Card {/** 牌面值 */private String name;/** 花色 */private String flower;/** 大小点数 */private int num;public Card() {}public Card(String name, String flower, int num) {super();this.name = name;this.flower = flower;this.num = num;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getFlower() {return flower;}public void setFlower(String flower) {this.flower = flower;}public int getNum() {return num;}public void setNum(int num) {this.num = num;}@Overridepublic String toString() {if (Objects.nonNull(flower)) {return name + "-" + num + "-" + flower;}return name + "-" + num;}}

玩家类:

/***     玩家类* */
public class Player {/**玩家id*/private int id;/**玩家姓名*/private String name;/**是否地主*/private boolean boss;/**牌集合*/private ArrayList<Card> cards=new ArrayList<Card>();public Player() {}public Player(int id, String name, boolean boss, ArrayList<Card> cards) {super();this.id = id;this.name = name;this.boss = boss;this.cards = cards;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public boolean isBoss() {return boss;}public void setBoss(boolean boss) {this.boss = boss;}public ArrayList<Card> getCards() {return cards;}public void setCards(ArrayList<Card> cards) {this.cards = cards;}@Overridepublic String toString() {return name+(boss?"(地主)":"")+":"+cards;}}

游戏管理类:

public class GameManage {/**声明所有牌的集合*/private static ArrayList<Card> all = new ArrayList<>();/**用于生成牌的牌面值*/private static String[] names = {"3","4","5","6","7","8","9","10","J","Q","K","A","2","Queen","King"};/**用于生成牌的花色*/private static String[] flowers = {"红桃","方块","梅花","黑桃"};/**所有玩家集合*/private ArrayList<Player> players = new ArrayList<Player>();/**声明随机数生成器*/private static Random randomGen = new Random();static {/******初始化所有牌******///笛卡尔积int i = 0;for (; i < names.length-2; i++) {for (int j = 0; j < flowers.length; j++) {Card c = new Card(names[i], flowers[j], i);all.add(c);}}//将大小王加入all.add(new Card(names[names.length-2],null,i++));all.add(new Card(names[names.length-1],null,i++));}/***    添加玩家*/public void addPlayer() {Scanner sc = new Scanner(System.in);System.out.println("请输入玩家1名称:");String name1 = sc.nextLine();System.out.println("请输入玩家2名称:");String name2 = sc.nextLine();System.out.println("请输入玩家3名称:");String name3 = sc.nextLine();Player p1 = new Player();p1.setId(1);p1.setName(name1);Player p2 = new Player();p2.setId(2);p2.setName(name2);Player p3 = new Player();p3.setId(3);p3.setName(name3);//将三名玩家加入集合players.add(p1);players.add(p2);players.add(p3);}/***   随机地主*/public void randomBoss() {//添加玩家addPlayer();//随机地主索引int i = randomGen.nextInt(players.size());//设置指定位置的玩家为地主players.get(i).setBoss(true);}/***   发牌*/public ArrayList<Player> sendCard() {//随机地主randomBoss();//对每一名玩家遍历for (Player p : players) {//先为每一位玩家随机发17张牌for (int i = 0; i < 17; i++) {//随机一张牌的索引int cardIndex = randomGen.nextInt(all.size());//获取随机索引位置的牌Card card = all.get(cardIndex);//将随机的牌加入当前遍历玩家的集合p.getCards().add(card);//从源集合中移除这张牌all.remove(card);}} //最后三张牌给地主for (Player p : players) {if(p.isBoss()) {//将all集合中的所有元素加入地主的集合p.getCards().addAll(all);}}return players;}}

测试类:

public static void main(String[] args) {ArrayList<Player> players = new GameManage().sendCard();for (Player p : players) {System.out.println(p);}
}

运行结果:

请输入玩家1名称:
刘备
请输入玩家2名称:
关羽
请输入玩家3名称:
张飞
刘备:[A-11-梅花, 4-1-梅花, 9-6-红桃, 8-5-梅花, A-11-方块, 8-5-黑桃, 6-3-红桃, 6-3-方块, K-10-方块, Queen-13, 10-7-梅花, K-10-梅花, Q-9-梅花, 2-12-红桃, Q-9-红桃, 6-3-梅花, 10-7-黑桃]
关羽:[5-2-黑桃, 9-6-黑桃, A-11-黑桃, 4-1-红桃, 5-2-红桃, 3-0-红桃, 5-2-方块, A-11-红桃, 6-3-黑桃, 5-2-梅花, 7-4-红桃, K-10-黑桃, 8-5-方块, 4-1-黑桃, 3-0-方块, Q-9-方块, 8-5-红桃]
张飞(地主):[10-7-方块, 2-12-黑桃, 7-4-梅花, 2-12-方块, 2-12-梅花, 4-1-方块, 7-4-黑桃, Q-9-黑桃, J-8-梅花, 7-4-方块, 3-0-梅花, J-8-方块, 3-0-黑桃, J-8-黑桃, 10-7-红桃, J-8-红桃, King-14, 9-6-方块, 9-6-梅花, K-10-红桃]

赵大超的学习周志(四)相关推荐

  1. 赵大超的学习周志(五)

    赵大超的学习周志(五) 本周是Java基础学习的第五周,学习内容包括对正则表达式的进一步补充学习,本周学习的重头戏是对集合框架的学习,集合包括单列集合和双列集合,单列集合的顶层接口为Collectio ...

  2. 赵大超的学习周志(八)

    赵大超的学习周志(八) 本周是Java学习的第八周,主要是对前端知识的学习,其中学习的内容包括H5和CSS,具体学习了H5中的各种标签元素,CSS中的使用方式,最后是对网页的设计和布局的学习,综合运用 ...

  3. 赵大超的学习周志(十)

    赵大超的学习周志(十) 本周是Java学习的第十周,主要是对Javascript的进一步学习和对jQuery的学习,其中包括进一步学习的BOM,JSON字符串,Ajax基础,jQuery入门基础,选择 ...

  4. 赵大超的学习周志(二)

    赵大超的学习周志(二) 本周是Java基础学习的第二周,学习内容包括对数组的复习和强化学习,对面向对象编程的初步学习,学习了类和对象,方法的相关使用知识,着重了解了面向对象的封装和继承两个属性,初步形 ...

  5. 赵大超的学习周志(六)

    赵大超的学习周志(六) 本周是Java学习的第六周,主要是对数据库的学习,其中包括对数据库的基本了解,MySQL的了解和使用,SQL语句的学习,对常用的sql数据类型的学习,对查询语句的学习和掌握是重 ...

  6. 赵大超的学习周志(七)

    赵大超的学习周志(七) 本周是Java学习的第七周,主要是对JDBC的学习,其中包括对JDBC的概述,JDBC的六大步骤,,基本的CRUD,简易的DBUtils封装,Statement与Prepare ...

  7. 学习周志(8.21)

    本周开始了C++语言的学习,下面是C++基础语法学习内容的一些整理:命名空间.输入输出.带默认值的函数.带占位参数的函数.函数重载.C++引用.new与delete. 1.命名空间: 命名空间用于解决 ...

  8. python周志_Python学习周志—第一周(入门知识)

    变量和简单数据类型 使用方法修改字符串 title() 首字母大写 upper() 字母大写 lower() 字母小写 split() 通过指定分隔符对字符串进行切片 加号(+)来合并字符串 使用制表 ...

  9. Python学习周志—第一周(入门知识)

    变量和简单数据类型 使用方法修改字符串 title() 首字母大写 upper() 字母大写 lower() 字母小写 split() 通过指定分隔符对字符串进行切片 加号(+)来合并字符串 使用制表 ...

最新文章

  1. 一张图,看编程语言十年热度变化
  2. Facebook发现:计算机识别系统更青睐识别“有钱人”,准确率高出20%
  3. 微服务常见安全认证方案Session token cookie跨域
  4. python数据分析图_Python数据分析:手把手教你用Pandas生成可视化图表的教程
  5. 如何通过Port-isolate实现二层网络相互隔离
  6. ehcache memcache redis 三大缓存男高音
  7. docker network 网络模式
  8. 景驰无人车总部落户广州:明年最低量产500辆,回应百度官司
  9. 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_2-3.热部署在Eclipse和IDE里面的使用...
  10. 计算机网络系统是由计算机系统,计算机网络由哪几部分组成?
  11. AD转换原理与方案设计(包含原理图、PCB和BOM表)
  12. 2021上半年教资综合素质——主观题
  13. mysql错误:Table XXX is marked as crashed and should be repaire
  14. android app闪退的原因分析,打开一个app就闪退解决方法
  15. 代码审计入门学习笔记
  16. 字符串转成可计算的数学表达式
  17. Html设置背景图模糊,CSS设置背景图片模糊内容不模糊的解决方法
  18. 下单以及订单处理流程描述
  19. 我平时总结的几个Python编程小技巧
  20. linux桌面无法显示U盘,电脑桌面右下角不能显示u盘图标解决方法

热门文章

  1. 人脸表情识别数据集:CK+
  2. 吃鸡服务器维护6月23日,4月23日吃鸡更新 | 手游网游页游攻略大全
  3. 退役后,他们在抖音找到人生的另一种可能
  4. IDEA 安装插件 Eval Reset
  5. CentOS 5.10安装无线网卡驱动全面总结
  6. Notepad++选中行操作 快捷键 使用技巧
  7. abab的四字成语_abab的四字词语大全
  8. 非京籍户口在北京办理退休条件?养老保险没缴够15年,如何在北京退休?详细讲解一下
  9. 盛诺基在科创板IPO终止:华西证券撤回保荐,原计划募资约20亿元
  10. 全国各地12306订票时间大集合