异常
异常的来源
一个健壮的程序应该会“条件反射”,当出现异常时,会产生异常抛出来表达出自己的不适用
throws声明方法需要检查的异常列表,throw 异常实例 try catch处理异常。
一个Java程序在遇到异常的时候(风险),它的处理机制是这样的:
1)将程序返回到安全状态下,提示程序的异常信息,让程序调用者可以执行其他处理方案。
2)程序不能直接被终结掉,应该让方法的调用者保存当前的状态,以适当的方式终止程序
Java中异常都来自于Throwable类的子类,主要有两个级别的一个是Error级别,另一个是Exception级别。
Error的特点:
1)Error是不可被控制的(unchecked);
2)Error用于表示系统级别的错误或者底层资源的错误;
3)如果要想处理Error,应该在系统的层面进行捕捉。
Exception的特点:
1)可被控制(checked) 或不可控制的(unchecked);
2)由程序员导致的错误;
3)异常都可以在应用程序层面进行处理。
编译时检查异常:是Exception的子类,这种异常必须要求在编译的时候进行检查处理否则无法编译。
运行时异常:是RuntimeException的子类,这种异常无需在编译阶段检查,在程序运行的过程中再进行检查的。
处理异常
捕获异常,使用try catch代码块检查异常出现的代码块。在catch中给出解决方案来对程序进行“补救”或者结束掉它
抛出异常,如果程序中无法确定如何处理该异常可以在方法声明出将其抛出给代码调用者让它来进行处理。程序的异常始终都要进行解决掉,最终抛出也只是会抛给你去进行处理,这是最糟糕的处理方式
不管程序运行是否出现异常,在finally中的代码块一定会被执行的。所以经常会借助于finally代码块做一些清理的工作。
捕获多个异常时,捕捉的有父子关系的,要先捕获子类,再捕获父类
自定义异常
在Java中要想创建自定义异常,需要继承Throwable或者他的子类Exception。
class 自定义异常类 extends 异常类型(Exception){
// 因为父类已经把异常信息的操作都完成了,所在子类只要在构造时,将异常信息传递给父类通过super 语句即可。
// 重写 有参 和 无参 构造方法
}
public class CustomException extends Exception {
//无参构造方法
public CustomException(){
super();
}
//有参的构造方法
public CustomException(String message){
super(message);
}
// 用指定的详细信息和原因构造一个新的异常
public CustomException(String message, Throwable cause){
super(message,cause);
}
//用指定原因构造一个新的异常
public CustomException(Throwable cause) {
super(cause);
}
}
JDK部分类
Math
java.lang.Math 这是一个数学计算类,我们知道java.util.Random也能进行随机数的生成,当然Math.random()也能进行随机数的生成。
其返回带正号的 double 值,该值大于等于 0.0 且小于 1.0。如果要生成0 <=num<10的整数需要两步
1)Math.random()*10(生成的是0<=num<10)
2)使用int进行强制类型转换将double转为int
public String randomDDD(){
String str = "";
for (int i=0; i<3; i++) {
str = str + (int)(Math.random() * 9 + 1);
}
return str;
}
Arrays
-
该类包含用于操作数组的各种方法(如排序和搜索)。
正则表达式
java.util.regex.Matcher;
java.util.regex.Pattern;
通过Matcher类对象的matches方法来检测一个字符串对指定的正则表达式是否匹配,在学习String类时会发现其中也有一个用来检测正则匹配的方法matches,实际上String类的matches方法内部调用的就是Matcher类的matches方法。
当然,Matcher和Pattern类的功能远不止如此,还可以用来进行数据爬取:
例如,有一个很长的文本内容(这里我们简化以下),其中有很多杂乱的信息以及一些手机号码,现在我们需要把手机号码全部爬取出来,那么可以这样来进行:
String info = "张三13888888888今天天气013655667788明天去哪里8613766558877,"
+ "天气不错,133668晴朗138998合肥13899996666很好";
Pattern pattern = Pattern.compile("(86)?0?1\\d{10}");
Matcher matcher=pattern.matcher(info);
while(matcher.find()){ // find查找与正则匹配的下一个子序列
String phone = matcher.group(); // group返回所find查找所匹配的子序列
System.out.println("爬取一个手机号:" + phone);
}
时间
操作时间的类有两个:
java.util.Calendar
java.util.Date
Date中很多方法都已经过时掉了(不推荐使用)。
在目前流行的JDK版本中Date类只是作为一种日期类型,不再作为操作日期的对象了。
但是怎么构造其他的时间呢?Date中的方法本来提供了方法,现在已经过时了,无法使用。
现在对日期的处理使用功能更加强大日历类Calendar。
现在对日期的处理使用功能更加强大日历类Calendar。
Calendar calendar=Calendar.getInstance();//通过工厂方法获取实例
calendar中提供了重载方法来设定时间
calendar.set(year, month, date);//设置年月(0-11)日 时分秒位当前时间 calendar.set(year, month, date, hourOfDay, minute, second);//设置年月日时分秒
注意:
月份是0-11,如设置12月,值填为11, 5月份值设置为4
Calendar calendar= Calendar.getInstance();
int rlt=0;
Date date1;
Date date2;
//获取当前日期 date1
date1=calendar.getTime();//em1
//设置时间为1995-09-01 12:20:20
calendar.set(1995,8,1,12,20,20);//em2
//再次获取时间date2
date2=calendar.getTime();//em3
//rlt=比较date1 和date2的大小
rlt=date1.compareTo(date2);//em4
if(rlt==0){
System.out.println("date1 equals date2");
}else if(rlt>0){
System.out.println("date1 more than date2");
}else if(rlt<0){
System.out.println("date1 less than date2");
}
将字符串按时间戳转为日期
public static Date str2Date(String date_str, String pattern)throws ParseException {
// TODO Auto-generated method stub
SimpleDateFormat dateFormat=new SimpleDateFormat(pattern);
Date d =dateFormat.parse(date_str);
return d;
}
将日期按时间戳转为字符串
public static String date2Str(Date date, String pattern) {
// TODO Auto-generated method stub
SimpleDateFormat dateFormat=new SimpleDateFormat(pattern);
String s=dateFormat.format(date);
return s;
}
字符串
字符串拼接不用“+”,用StringBuilder
那么问题来了,看起来是使用StringBuilder的代码写起来并没有+来得更简洁和简便呢。
代码不重要,主要看性能,
String是一个不可变的字符串,这样的拼接语句实际上创建了多个字符串对象。
String str="abc";//创建一个字符对象 str=str+"def";//对象不可变,重新将拼接后的值创建新的对象
每次的拼接会创建一个新的字符串对象,对象的创建开销是很大的。
反过来看下StringBuilder,是可变的字符串,不管拼接多少次都是只创建一个对象。系统的开销就很小了。
StringBuilder和StringBuffer是有什么不同呢?
StringBuilder和StringBuffer在使用的时候没有任何区别,它们的方法、构造函数签名都是一样的。
那为何还要提供两个功能相同的API来作为字符串的操作呢?当然是有内部区别的。
在多线程的情况下使用StringBuffer保证数据的同步。在单线程情况下两个都可以用,StringBuilder会快一些。
indexOf(String str)查找子字符串,
insert()在指定位置添加字符串,
delete(int start, int end)删除子串,
replace()使用给定String中的字符替换此序列的子字符串中的字符,
reverse()将此字符序列用其反转形式取代,
substring()截取子串等等。
大数运算
浮点数由于在计算机中存储过程中转换为二进制时,受精度的影响,并非是其原值,而是一个近似值,因此想要进行精确计算就需要其他的方式来进行。
另外,在某些特殊场合下需要计算非常大的数,包括大整数和大浮点数,而这些数我们使用内置类型是存储不下的,同样需要其他的方式来进行。
这里介绍两个类,就是来进行相关的大数及精确计算的:BigInteger类和BigDecimal类,分别用来表示大整数类和大浮点数类,且在理论上只要内存足够大就能够表示无限大的数。
常用构造方法:
public BigInteger(String val); 使用字符串形式的整数值来进行构造
常用成员方法:
public BigInteger add(BigInteger val) 加法运算,返回值为(this+val)的新对象
public BigInteger subtract(BigInteger val) 减法运算,返回值为(this-val)的新对象
public BigInteger multiply(BigInteger val) 乘法运算,返回值为(this * val)的新对象
public BigInteger divide(BigInteger val) 除法运算,返回值为(this /val)的新对象
public BigInteger remainder(BigInteger val) 求余运算,返回值为(this % val)的新对象
public BigInteger[] divideAndRemainder(BigInteger val) 除法求余运算,返回一个数组包含除法和求余结果
对于浮点数的运算,经常需要考虑控制小数部分的精度,有几种比较常用的控制方法:
1. BigDecimal类中的setScale方法
BigDecimal a = new BigDecimal("3.1415926");
a = a.setScale(3, BigDecimal.ROUND_HALF_UP); // 返回一个新的大浮点数对象,保留小数点后3位,且指定为四舍五入
System.out.println(a); // 输出3.142
2. String.format方法
double a = 3.1415926;
String str = String.format("%.3f", a); // 返回的是一个字符串,保留小数点后3位,默认四舍五入
System.out.println(str); // 输出3.142
3. NumberFormat类中的setMaximumFractionDigits方法
BigDecimal a = new BigDecimal("3.1415926");
NumberFormat nf = NumberFormat.getInstance();
nf.setMaximumFractionDigits(3); // 设置保留小数点后最多几位
String str = nf.format(a.doubleValue()); // 对大浮点数进行格式化,返回字符串
System.out.println(str); // 输出3.142
4. DecimalFormat类中的setRoundingMode和format方法
BigDecimal a = new BigDecimal("3.1415926");
DecimalFormat df = new DecimalFormat("#0.000"); // 指定数字模式,小数点后保留三位
df.setRoundingMode(RoundingMode.FLOOR); // 指定省略模式,此处为向下省略
String str = df.format(a.doubleValue()); // 格式化,返回字符串
System.out.println(str); // 输出3.141
国际化
国际化的实现需要以下几个类的支撑:
1.Java.util.Locale:用于封装一个特定的国家/地区、语言环境
2.Java.util.ResourceBundle:用于加载和访问资源文件
3.Java.text.MessageFormat:格式化带占位符的字符串