第1章 异常与异常处理
什么是异常?
概念:有异于常态,和正常情况不一样,有错误出现。在编程上来讲我们把那些阻止当前方法或作用域继续执行的问题,我们称之为异常
异常处理的作用和意义:
将异常提示给编程人员或用户,使本来已经中断的程序以适当的方式继续运行或者退出并且能够保存用户的当前操作或者进行数据回滚,最后再把占用的资源释放掉。
1.Error:jvm中出现不可恢复的错误,如堆内存溢出等,程序是没有处理机会的。
2.RuntimeException(运行时异常):属于非检查异常,java编译器 忽略其抛出和检查,当在加载运行后,出现的异常;
3.非运行时异常(受检查异常):程序编译时,就提示的异常。必须被捕获,或者在函数中声明为抛出该异常。自定义异常、IOException、SQLException、FileNotFoundException等。
try-catch以及try-catch-finally
try{
//一些会抛出的异常
}catch(Exception e){
//处理该异常的代码块
}finally{
//最终要执行的代码
}
一旦try中发现异常,程序的控制权将被移交给catch块中的异常处理程序。【try 语句块不可以独立存在,必须与 catch 或者 finally 块同存】
catch块如何处理?比如发出警告:提示、检查配置、网络连接,记录错误/日志等。(try catch 语句块中都没有return时,程序会从语句块外部读取)
try会抛出很多种类型的异常,多个catch块捕获多种错误。
try{
//一些会抛出的异常
}catch(Exception e){
//处理该异常的代码块
}catch(Exception2 e){
//处理该异常Exception2 的代码块
}..(n个catch块)...{
..........
}finally{
//最终要执行的代码
//可用于关闭和释放资源等
}
多重 catch 语句中,异常类型必须子类在前父类在后(就近原则)(顺序不对编译时也会提醒错误)。
当有finally时,该语句块中的程序会在try-catch后执行【即使try/catch有return】,返回调用前执行。
catch 块有一个参数,该参数是某种异常类的对象
可以使用 throw 语句抛出异常
Java中的异常抛出
throw——将产生的异常抛出(动作,写在方法体里头,他表明的是具体的抛出)
throws——声明将要抛出何种类型的异常(声明)(可以抛出一种类型的异常也可以抛出多种类型的异常,每个类型的异常用逗号隔开)
public void 方法名(参数列表)throws 异常列表{
//调用会抛出异常的方法或者:
throw new Exception();
}
自定义异常(必须继承于Java标准类库中意思相近的异常类型或者直接继承于所有异常类型的基类也就是Exception类型)
class 自定义异常类 extends 异常类型{
}
异常链
把捕获的异常包装成一个新的异常,然后在新的异常里添加对原始异常的引用,再把这个新异常抛出,他们像是链式反应一样,一个导致另一个,在Java中这种情况就叫异常链。
捕获到的异常,可以在当前方法的 catch 块中处理,也可抛出给调用者去处理
第2章 认识Java中的字符串
Java 中字符串的不变性
String 对象创建后则不能被修改,是不可变的,所谓的修改其实是创建了新的对象,所指向的内存空间不同。
1、 通过 String s1=“爱慕课”; 声明了一个字符串对象, s1 存放了到字符串对象的引用。
然后通过 s1=“欢迎来到:”+s1; 改变了字符串 s1 ,其实质是创建了新的字符串对象,变量 s1 指向了新创建的字符串对象。
2、 一旦一个字符串在(堆内存)内存中创建,则这个字符串将不可改变。如果需要一个可以改变的字符串,我们可以使用StringBuffer或者StringBuilder
3、每次 new 一个字符串就是产生一个新的对象,即便两个字符串的内容相同,使用 ”==” 比较时也为 ”false” ,如果只需比较内容是否相同,应使用 ”equals()” 方法。
常量字符串,多次出现时会被编译器优化,只创建一个对象
public class HelloWorld {
public static void main(String[] args) {
String s1 = "imooc";
String s2 = "imooc";
//定义字符串s3,保存“I love”和s1拼接后的内容
String s3="I love " + s1;
// 比较字符串s1和s2
// 【imooc为常量字符串,多次出现时会被编译器优化,只创建一个对象】
System.out.println("s1和s2内存地址相同吗?" + (s1 == s2));
//比较字符串s1和s3
System.out.println("s1和s3内存地址相同吗?" + (s1 == s3) );
String s4 = "I love " + s1;
//比较字符串s4和s3
// s1是变量,s4在运行时才知道具体值,所以s3和s4是不同的对象
System.out.println("s3和s4内存地址相同吗?" + (s4 == s3));
}
}
//输出结果:
s1和s2内存地址相同吗?true
s1和s3内存地址相同吗?false
s3和s4内存地址相同吗?false
String 类的常用方法
//运行结果:
字符串长度:10
字符‘编’的位置:8
字符串"JAVA"的位置:3
字符串"imooc"的位置:-1
按空格拆分成数组:【学习,JAVA,编程】
获取位置[3,7)之间的字符串:JAVA
- 字符串 str 中字符的索引从0开始,范围为 0 到 str.length()-1
- 使用 indexOf 进行字符或字符串查找时,如果匹配返回位置索引;如果没有匹配结果,返回 -1
- 使用 substring(beginIndex , endIndex) 进行字符串截取时,包括 beginIndex 位置的字符,不包括 endIndex 位置的字符【
[左闭,右开)左包含,右不包含
】
String str="学习 JAVA 编程";
//转换为小写 str.toLowerCase();学习 java 编程
//获取索引位置为i的字符:str.charAt(i);
//将字符转换为byte[],并输出
byte[] b=str.getBytes();
for(int i=0;i<b.length;i++){
//输出b[i]
//-47 -89 -49 -80 32 74 65 86 65 32 -79 -32 -77 -52
}
String str2=new String("学习 JAVA 编程");
str==str2 -->false 内存地址不相同
str.equals(str2) -->true 内容相同
如果比较对象是值变量:只用==,值类型是不存在equals()的。
==” 和 equals() 有什么区别呢?(针对字符串)
==: 判断两个字符串内存地址是否相同,即判断是否是同一个字符串对象
equals(): 比较存储在两个字符串对象中的**内容(值)**是否一致【内存空间里面的值】
String s = "abcd";
s中保存了string对象的引用。图中箭头可以理解为“存储他的引用”。
String s2 =s;
s2保存了相同的引用值,因为他们代表同一个对象。
String s1=new String("abcd");//new 创建了一个新的对象
//s与s2 指向是完全相同的存储地址。是同一个对象【==、equals()都为true】
//s与s1 指向是不相同的存储地址。不是同一个对象【==为false】、但是里面的值相同【equals()为true】
//Java中默认的 Object的equals()方法 实现如下:
public boolean equals(Object obj) {
//比较的是对象的【引用】是否指向同一块内存地址。
return (this == obj);
}
//而String类则【覆写了这个方法】,直观的讲就是比较字符是不是都相同。(比较的是【内容/值】)
public boolean equals(Object anObject) {
if (this == anObject) {//指向同一块内存地址 肯定相等
return true;
}
if (anObject instanceof String) {//指向不同一块内存地址时 判断里面的内容是否相等
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
字节是计算机存储信息的基本单位,1 个字节等于 8 位, gbk 编码中 1 个汉字字符存储需要 2 个字节,1 个英文字符存储需要 1 个字节。所以我们看到上面的程序运行结果中,每个汉字对应两个字节值,如“学”对应 “-47 -89” ,而英文字母 “J” 对应 “74” 。同时,我们还发现汉字对应的字节值为负数,原因在于每个字节是 8 位,最大值不能超过 127,而汉字转换为字节后超过 127,如果超过就会溢出,以负数的形式显示。
StringBuilder 类(线程不安全)
StringBuffer 是线程安全的,而 StringBuilder 则没有实现线程安全功能,所以性能略高。因此一般情况下,如果需要创建一个内容可变的字符串对象,应优先考虑使用 StringBuilder 类。
StringBuilder str=new StringBuilder("hello");
str.append(" imooc");
str.append(520);
//输出长度 str.length();-->14
//插入前str:-->hello imooc520
str.insert(11,"!");
String str2=str.toString();
//插入后str2:-->hello imooc!520
创建了 StringBuilder 对象,用来存储字符串,并对其做了追加和插入操作。这些操作修改了 str 对象的值,而没有创建新的对象,这就是 StringBuilder 和 String 最大的区别。
比较
性能上通常StringBuilder > StringBuffer > String
第3章 Java 中必须了解的常用类
Java 中的包装类
为了让基本数据类型也具备对象的特性, Java 为每个基本数据类型都提供了一个包装类,这样我们就可以像操作对象那样来操作基本数据类型。
包装类主要提供了两大类方法:
- 将本类型和其他基本类型进行转换的方法
- 将字符串和本类型及包装类互相转换的方法
单选题
每一个基本数据类型,都对应一个包装类
基本类型不可调用方法
包装类都在 java.lang 包中
包装类提供了在不同类型间进行转换的方法
Java 中基本类型和包装类之间的转换
装箱:把基本类型转换成包装类,使其具有对象的性质,又可分为手动装箱和自动装箱
int i=10;//定义一个int基本类型值
Integer x=new Integer(i);//手动装箱
Integer y=i;//自动装箱
拆箱:和装箱相反,把包装类对象转换成基本类型的值,又可分为手动拆箱和自动拆箱
Integer j=new Integer(8);
int m=j.intValue();//手动拆箱为int类型
int n=j;//自动拆箱为int类型
Java 中基本类型和字符串之间的转换
基本类型转换为字符串:
int c=10;
String str1=Integer.toString(c);//1、使用包装类的 toString() 方法
String str2=String.valueOf(c);//2、使用String类的 valueOf() 方法
String str3=c+"";//3、用一个空字符串加上基本类型,得到的就是基本类型数据对应的字符串
字符串转换成基本类型:
String str="8";
int d=Integer.parseInt(str);//1. 调用包装类的 parseXxx 静态方法
int e=Integer.valueOf(str);//2. 调用包装类的 valueOf() 方法转换为基本类型的包装类,会自动拆箱
使用 Date 和 SimpleDateFormat 类表示时间
- 使用 format() 方法将日期转换为指定格式的文本
- 使用 parse() 方法将文本转换为日期
注意
1、 调用 SimpleDateFormat 对象的 parse() 方法时可能会出现转换异常,即 ParseException ,因此需要进行异常处理
2、 使用 Date 类时需要导入 java.util 包,使用 SimpleDateFormat 时需要导入 java.text 包
Calendar 类的应用
仅推荐使用 Calendar 类进行时间和日期的处理。
java.util.Calendar 类是一个抽象类,可以通过调用 getInstance() 静态方法获取一个 Calendar 对象,此对象已由当前日期时间初始化,即默认代表当前时间,如 Calendar c = Calendar.getInstance();
Calendar c = Calendar.getInstance();//创建对象
int year=c.get(Calendar.YEAR);
int month=c.get(Calendar.MONTH)+1;//0表示1月。所以加1
int day=c.get(Calendar.DATE);
int hour=c.get(Calendar.HOUR_OF_DAY );//小时
int minute=c.get(Calendar.MINUTE);
int second=c.get(Calendar.SECOND);
调用 Calendar 类的 getInstance() 方法获取一个实例,然后通过调用 get() 方法获取日期时间信息,参数为需要获得的字段的值, Calendar.Year 等为 Calendar 类中定义的静态常量。
Calendar 类提供了 getTime() 方法,用来获取 Date 对象,完成 Calendar 和 Date 的转换,还可通过 getTimeInMillis() 方法,获取此 Calendar 的时间值,以毫秒为单位。
Date date=c.getTime();//转化为Date()对象
Long time=c.getTimeInMillis();//获取当前毫秒数
public static void main(String[] args) {
// 创建Calendar对象
Calendar c = Calendar.getInstance();
int today=c.get(Calendar.DATE);
System.out.println("当前日期todate:" + today);
// 将Calendar对象转换为Date对象
Date date = c.getTime();
System.out.println("当前时间date:" + date);
// 创建SimpleDateFormat对象,指定目标格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 将日期转换为指定格式的字符串
String now = sdf.format(date);
System.out.println("当前时间now:" + now);
}
//输出:
当前日期todate:28
当前时间date:Mon May 28 17:08:12 CST 2018
当前时间now:2018-05-28 17:08:12
使用 Math 类操作数据
强制类型转换:12
四舍五入:13
floor:12.0
ceil:13.0
随机数:0.46833692976879813
产生[0,99)之间的随机整数:30