目录
1、异常机制本质
2、异常的处理
3、数组的声明
4、数组的初始化
5、数组的遍历
6、数组的拷贝
7、java.util.Arrays类
8、多维数组
9、冒泡排序
10、包装类
11、String类、StringBuffer类和StringBuilder类
12、时间相关的类
13、Math类
14、File类
15、枚举类型
1、异常机制本质
就是当程序出现错误,程序安全退出的机制,Java是采用面向对象的方式来处理异常抛出异常:在执行一个方法时,如果发生异常,则这个方法生成代表该异常的一个对象,停止当前执行路径,并把异常对象提交给JRE捕获异常:JRE得到该异常后,在方法的调用栈中查找,从生成异常的方法开始回溯,直到找到相应的异常处理代码为止
Error:程序无法处理的错误,表示运行应用程序中较严重问题,一般编程操作无法处理Exception:程序本身能够处理的异常,如空指针异常(NullPointerException)、数组下标越界异常(ArrayIndexOutOfBoundsException)、类型转换异常(ClassCastException)、算术异常(ArithmeticException)等RuntimeException:如被 0 除、数组下标越界、空指针等,通常是由编程错误导致的Checked Exception:所有不是RuntimeException的异常的统称,又被称为“已检查异常”,如IOException、SQLException等以及用户自定义的Exception异常。这类异常在编译时就必须做出处理,否则无法通过编译。
2、异常的处理
捕捉异常:捕获异常通过3个关键词来实现:try-catch-finally。用try来执行一段程序,如果出现异常,系统抛出一个异常,可以通过它的类型来捕捉(catch)并处理它,最后通过finally语句为异常处理提供一个统一的出口,finally所指定的代码都要被执行(catch语句可有多条,finally语句最多只能有一条)。声明异常:在一些情况下,当前方法并不需要处理发生的异常,而是向上传递给调用它的方法处理,或者当CheckedException产生时,不一定立刻处理它,可以再把异常throws出去。如果一个方法中可能产生某种异常,但是并不能确定如何处理这种异常,则应根据异常规范在方法的首部声明该方法可能抛出的异常。如果一个方法抛出多个已检查异常,就必须在方法的首部列出所有的异常,之间以逗号隔开。自定义异常:在程序中,可能会遇到JDK提供的任何标准异常类都无法充分描述清楚我们想要表达的问题,这种情况下可以创建自己的异常类,即自定义异常类。自定义异常类只需从Exception类或者它的子类派生一个子类即可。自定义异常类如果继承Exception类,则为受检查异常,必须对其进行处理;如果不想处理,可以让自定义异常类继承运行时异常RuntimeException类。习惯上,自定义异常类应该包含2个构造器:一个是默认的构造器,另一个是带有详细信息的构造器:
class IllegalAgeException extends Exception {
//默认构造器
public IllegalAgeException() {
}
//带有详细信息的构造器,信息存储在message中
public IllegalAgeException(String message) {
super(message);
}
}
3、数组的声明
//创建基本类型一维数组
public class Test {
public static void main(String args[]) {
int[] s = null; // 声明数组;
s = new int[10]; // 给数组分配空间;
for (int i = 0; i < 10; i++) {
s[i] = 2 * i + 1;//给数组元素赋值;
}
}
}
//创建引用类型一维数组
class Man{
private int age;
private int id;
public Man(int id,int age) {
super();
this.age = age;
this.id = id;
}
}
public class Test {
public static void main(String[] args) {
Man[] mans; //声明引用类型数组;
mans = new Man[10]; //给引用类型数组分配空间;
Man m1 = new Man(1,11);
Man m2 = new Man(2,22);
mans[0]=m1;//给引用类型数组元素赋值;
mans[1]=m2;//给引用类型数组元素赋值;
}
}
声明的时候数组并没有真正创建,只有在实例化数组对象时,JVM才分配空间
4、数组的初始化
静态初始化:在定义数组的同时就为数组元素分配空间并赋值
int[] a = { 1, 2, 3 };// 静态初始化基本类型数组;
Man[] mans = { new Man(1, 1), new Man(2, 2) };// 静态初始化引用类型数组; 动态初始化:数组定义与为数组元素分配空间并赋值的操作分开进行 int[] a1 = new int[2];//动态初始化数组,先分配空间; a1[0]=1;//给数组元素赋值; a1[1]=2;//给数组元素赋值;默认初始化:数组一经分配空间,其中的元素也按照实例变量同样的方式被隐式初始化
int a2[] = new int[2]; // 默认值:0,0 boolean[] b = new boolean[2]; // 默认值:false,false String[] s = new String[2]; // 默认值:null, null
5、数组的遍历
采用一般循环也可以遍历数组,但JDK1.5新增加了for-each循环,专门用于数组遍历:
public class Test {
public static void main(String[] args) {
String[] ss = { "aa", "bbb", "ccc", "ddd" };
for (String temp : ss) {
System.out.println(temp);
}
}
} 但是使用该方法遍历数组时无法对元素进行修改
6、数组的拷贝
System类里包含了static void arraycopy(object src,int srcpos,object dest, int destpos,int length)方法,该方法可以将src数组里的元素赋给dest数组的元素srcpos:指定从src数组的第几个元素开始赋值length:指定将src数组的多少个元素赋给dest数组的元素
public class Test {
public static void main(String args[]) {
String[] s = {"A","B","C","D","E"};
String[] sBak = new String[6];
System.arraycopy(s,0,sBak,0,s.length);//数组的拷贝
}
}
7、java.util.Arrays类
JDK提供的java.util.Arrays类包含了常用的数组操作,包括排序、查找、填充、打印内容等打印数组:
System.out.println(Arrays.toString(a));数组元素排序:
Arrays.sort(a);数组元素是引用类型的排序(Comparable接口的应用):
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
Man[] msMans = { new Man(3, "a"), new Man(60, "b"), new Man(2, "c") };
Arrays.sort(msMans);
System.out.println(Arrays.toString(msMans));
}
}
class Man implements Comparable {
int age;
int id;
String name;
public Man(int age, String name) {
super();
this.age = age;
this.name = name;
}
public String toString() {
return this.name;
}
public int compareTo(Object o) {
Man man = (Man) o;
if (this.age < man.age) {
return -1;
}
if (this.age > man.age) {
return 1;
}
return 0;
}
} 二分法查找: import java.util.Arrays;
public class Test {
public static void main(String[] args) {
int[] a = {1,2,323,23,543,12,59};
System.out.println(Arrays.toString(a));
Arrays.sort(a); //使用二分法查找,必须先对数组进行排序;
System.out.println(Arrays.toString(a));
//返回排序后新的索引位置,若未找到返回负数。
System.out.println("该元素的索引:"+Arrays.binarySearch(a, 12));
}
} 数组填充: import java.util.Arrays;
public class Test {
public static void main(String[] args) {
int[] a= {1,2,323,23,543,12,59};
System.out.println(Arrays.toString(a));
Arrays.fill(a, 2, 4, 100); //将2到4索引的元素替换为100;
System.out.println(Arrays.toString(a));
}
}
8、多维数组
二维数组的声明:
public class Test {
public static void main(String[] args) {
// Java中多维数组的声明和初始化应按从低维到高维的顺序进行
int[][] a = new int[3][];
a[0] = new int[2];
a[1] = new int[4];
a[2] = new int[3];
// int a1[][]=new int[][4];//非法
}
} 二维数组的静态初始化: public class Test {
public static void main(String[] args) {
int[][] a = { { 1, 2, 3 }, { 3, 4 }, { 3, 5, 6, 7 } };
System.out.println(a[2][3]);
}
} 二维数组的动态初始化: public class Test {
public static void main(String[] args) {
int[][] a = new int[3][];
// a[0] = {1,2,5}; //错误,没有声明类型就初始化
a[0] = new int[] { 1, 2 };
a[1] = new int[] { 2, 2 };
a[2] = new int[] { 2, 2, 3, 4 };
}
}
9、冒泡排序
比较相邻的元素,如果第一个比第二个大,就交换他们两个;对每一对相邻元素作同样的工作直到结尾的最后一对,此时最后的元素应该是最大的数;对除了该次操作中最后一个元素外所有元素,重复以上步骤;直到最后只剩下开始的一对元素并且完成比较,此时第一个元素应该是最小的数。 import java.util.Arrays;
public class Test {
public static void main(String[] args) {
int[] values = { 3, 1, 6, 2, 9, 0, 7, 4, 5, 8 };
bubbleSort(values);
System.out.println(Arrays.toString(values));
}
public static void bubbleSort(int[] values) {
int temp;
for (int i = 0; i < values.length; i++) {
for (int j = 0; j < values.length - 1 - i; j++) {
if (values[j] > values[j + 1]) {
temp = values[j];
values[j] = values[j + 1];
values[j + 1] = temp;
}
}
}
}
}
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
int[] values = { 3, 1, 6, 2, 9, 0, 7, 4, 5, 8 };
bubbleSort(values);
System.out.println(Arrays.toString(values));
}
public static void bubbleSort(int[] values) {
int temp;
for (int i = 0; i < values.length; i++) {
for (int j = 0; j < values.length - 1 - i; j++) {
if (values[j] > values[j + 1]) {
temp = values[j];
values[j] = values[j + 1];
values[j + 1] = temp;
}
}
}
}
} 优化:可以增加逻辑判断,判断每一趟是否发生了数组元素的交换,如果没有发生,则说明此时数组已经有序,可以中止比较。
10、包装类
Java是面向对象的语言,但基本数据类型不是对象,包装类可以将基本数据转化成对象,以便于操作。
八个类中除了Character和Boolean外都是数字型,而数字型都是java.lang.Number的子类。Number类是抽象类,提供了抽象方法:intValue()、longValue()、floatValue()、doublevalue(),意味着所有的数字型包装类都可以互相转型。
public class Test {
void testInteger() {
// 基本类型转化成Integer对象
Integer int1 = new Integer(10);
Integer int2 = Integer.valueOf(20); // 官方推荐这种写法
// Integer对象转化成int
int a = int1.intValue();
// 字符串转化成Integer对象
Integer int3 = Integer.parseInt("334");
Integer int4 = new Integer("999");
// Integer对象转化成字符串
String str1 = int3.toString();
// 一些常见int类型相关的常量
System.out.println("int能表示的最大整数:" + Integer.MAX_VALUE);
}
public static void main(String[] args) {
Test test = new Test();
test.testInteger();
}
} JDK1.5后,Java引入了自动装箱(autoboxing)/拆箱(unboxing) Integer i = 5; //自动装箱 int j = i; //自动拆箱自动装箱:基本类型的数据处于需要对象的环境中时,会自动转为“对象”,即自动执行了valueOf()方法自动拆箱:每当需要一个值时,对象会自动转成基本数据类型,即自动执行了xxxValue()方法包装类空指针异常问题:当对象为null时,表示没有指向任何对象的实体,如果进行自动拆箱,就会出现NullPointerException错误包装类的缓存问题:包装类在自动装箱时为了提高效率,对于-128~127之间的值会进行缓存处理,超过范围后,对象之间不能再使用“==”进行数值的比较,而是使用equals方法
11、String类、StringBuffer类和StringBuilder类
String类的对象代表不可变的Unicode字符序列,内部的成员变量的值无法再改变StringBuffer类的对象代表可变的字符序列,是JDK1.0版本提供的类,线程安全,做线程同步检查, 效率较低StringBuilder类的对象也代表可变的字符序列,是JDK1.5版本提供的类,线程不安全,不做线程同步检查,因此效率较高,一般采用该类String类对字符串的操作实际上是对其副本的操作,原来的字符串一点都没有改变,如果多次执行会导致大量副本字符串对象存留在内存中,降低效率。而StringBuilder和StringBuffer类是对原字符串本身操作的,可以对字符串进行修改而不产生副本拷贝或者产生少量的副本,因此可以在循环中使用。
StringBuffer/StringBuilder类常用方法
public StringBuilder append(…)方法:为该StringBuilder 对象添加字符序列,返回自身对象public StringBuilder delete(int start,int end)方法:删除从start到end-1的字符序列,返回自身对象public StringBuilder deleteCharAt(int index)方法:移除此序列指定位置上的字符,返回自身对象public StringBuilder insert(…)方法:为该StringBuilder 对象在指定位置插入字符序列,返回自身对象public StringBuilder reverse()方法:将字符序列逆序,返回自身对象public String toString()方法:返回此序列中数据的字符串表示形式
public class Test {
public static void main(String[] args) {
//StringBuilder
StringBuilder sb = new StringBuilder();
sb.append('a');//追加单个字符
System.out.println(sb.toString());//转换成String输出
sb.append(" and b");//追加字符串
System.out.println(sb.toString());
//StringBuffer
StringBuffer sb2 = new StringBuffer("d");
sb2.insert(0, " and ").insert(0, "c");//插入字符串
System.out.println(sb2);
sb2.delete(0, 2);//删除子字符串
System.out.println(sb2);
sb2.deleteCharAt(0);//删除某个字符
System.out.println(sb2.charAt(0));//获取某个字符
System.out.println(sb2.reverse());//字符串逆序
}
12、时间相关的类
时间用long类型的变量来表示
Date类(较为过时)
import java.util.Date;
public class Test{
public static void main(String[] args) {
//默认是当前时间,按年月日时分秒的时间格式
Date date1 = new Date();
System.out.println(date1.toString());
//转换为自标准基准时间(1970年1月1日00:00:00 GMT)以来的毫秒数
long i = date1.getTime();
Date date2 = new Date(i - 1000);
System.out.println(date1.after(date2)); //测试此日期是否在指定日期之后
System.out.println(date1.before(date2)); //测试此日期是否在指定日期之前
System.out.println(date1.equals(date2)); //测试两个日期是否相同
//转换为时间格式
System.out.println(new Date(1000L * 60 * 60 * 24 * 365 * 39L).toString());
}
}
DateFormat类和SimpleDateFormat类
该类的作用是将时间对象转化成指定格式的字符串,胡者将指定格式的字符串转化成时间对象DateFormat是一个抽象类,一般使用它的的子类SimpleDateFormat类来实现功能
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Test {
public static void main(String[] args) throws ParseException {
// new出SimpleDateFormat对象
SimpleDateFormat s1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
// 将时间对象转换成字符串
String daytime = s1.format(new Date());
System.out.println(daytime);
System.out.println(new SimpleDateFormat("hh:mm:ss").format(new Date()));
// 将符合指定格式的字符串转成成时间对象
String time = "2007-10-7 20:15:30";
Date date = s1.parse(time);
System.out.println("date: " + date);
}
} 格式化字符:
Calendar日历类
Calendar 类是一个抽象类,一般由子类GregorianCalendar为我们提供关于日期计算的相关功能,比如年月日时分秒的展示和计算,还提供了世界上大多数国家/地区的标准日历系统注意月份的表示,一月是0,二月是1,以此类推,12月是11
import java.util.*;
public class Test {
public static void main(String[] args) {
// 创建日历对象
GregorianCalendar calendar = new GregorianCalendar(1999, 10, 9, 22, 10, 50);
int year = calendar.get(Calendar.YEAR); // 年,打印:1999
int month = calendar.get(Calendar.MONTH); // 月,打印:10
// Calendar.DATE和Calendar.DAY_OF_MONTH同义
int day = calendar.get(Calendar.DAY_OF_MONTH); // 日,打印:9
int day2 = calendar.get(Calendar.DATE); // 日,打印:9
int date = calendar.get(Calendar.DAY_OF_WEEK); // 星期,打印:3
System.out.println(year+" "+month+" "+day+" "+day2+" "+date);
// 设置日期
calendar.set(Calendar.YEAR, 2022);
calendar.set(Calendar.MONTH, Calendar.FEBRUARY);//父类Calendar用英文单词常量表示月份
calendar.set(Calendar.DATE, 13);//会自动计算星期
calendar.set(Calendar.HOUR_OF_DAY, 10);
calendar.set(Calendar.MINUTE, 20);
calendar.set(Calendar.SECOND, 23);
printCalendar(calendar);
// 日期计算
calendar.add(Calendar.MONTH, 7); // 月份加7
calendar.add(Calendar.DATE, -7); // 天数减7
printCalendar(calendar);
// 日历对象和时间对象转化
Date d = calendar.getTime(); //日历对象转换为时间对象
GregorianCalendar calendar0 = new GregorianCalendar();
calendar0.setTime(d); //时间对象转换为日历对象
}
//打印日历对象的函数
static void printCalendar(Calendar calendar) {
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1;
int day = calendar.get(Calendar.DAY_OF_MONTH);
int date = calendar.get(Calendar.DAY_OF_WEEK) - 1; // 星期几
String week = "" + ((date == 0) ? "日" : date);
int hour = calendar.get(Calendar.HOUR);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
System.out.printf("%d年%d月%d日,星期%s %d:%d:%dn", year, month, day,
week, hour, minute, second);
}
} 可以利用GregorianCalendar类,打印当前月份的日历: import java.text.ParseException;
import java.util.*;
public class Test {
public static void main(String[] args) throws ParseException {
System.out.println("请输入日期(格式为:1900-1-1):");
Scanner scanner = new Scanner(System.in);
String dateString = scanner.nextLine();
// 将输入的字符串转化成日期类
System.out.println("您刚刚输入的日期是:" + dateString);
String[] str = dateString.split("-");
int year = Integer.parseInt(str[0]);
int month = Integer.parseInt(str[1]);
int day = Integer.parseInt(str[2]);
Calendar c = new GregorianCalendar(year, month-1, day);
//也可以将字符串通过SImpleDateFormat转化成Date对象,再转化成日历类
c.set(Calendar.DATE, 1);
int dow = c.get(Calendar.DAY_OF_WEEK); // week:1-7 日一二三四五六
System.out.println("日t一t二t三t四t五t六");
for (int i = 0; i < dow - 1; i++) {
System.out.print("t");
}
int maxDate = c.getActualMaximum(Calendar.DATE);
for (int i = 1; i <= maxDate; i++) {
StringBuilder sBuilder = new StringBuilder();
if (c.get(Calendar.DATE) == day) {
sBuilder.append(c.get(Calendar.DATE) + "*t");
} else {
sBuilder.append(c.get(Calendar.DATE) + "t");
}
System.out.print(sBuilder);
if (c.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
System.out.print("n");
}
c.add(Calendar.DATE, 1);
}
}
}
13、Math类
public class Test {
public static void main(String[] args) {
System.out.println(Math.ceil(3.2)); //大于a的最小整数
System.out.println(Math.floor(3.2)); //小于a的最大整数
System.out.println(Math.round(3.2)); //double型转换为long型(四舍五入)
System.out.println(Math.abs(-45)); //a的绝对值
System.out.println(Math.sqrt(64)); //a的平方根
System.out.println(Math.pow(5, 2)); //a的b次幂
System.out.println(Math.PI); //圆周率
System.out.println(Math.E); //自然常数
System.out.println(Math.sin(Math.PI/6)); //余弦函数
System.out.println(Math.asin(0.5)); //余弦函数
System.out.println(Math.random()); // [0,1)的随机数
}
}
Math类无需导入,属于 java.lang复杂随机数可以使用java.util包下的Random类产生:
import java.util.Random;
public class Test {
public static void main(String[] args) {
Random rand = new Random();
//随机生成int类型允许范围之内的整型数据
System.out.println(rand.nextInt());
//随机生成[0,10)之间的int类型的数据
System.out.print(rand.nextInt(10));
//随机生成[20,30)之间的int类型的数据
System.out.print(20 + rand.nextInt(10));
//随机生成[0,1)之间的double类型的数据
System.out.println(rand.nextDouble());
//随机生成[0,1)之间的float类型的数据
System.out.println(rand.nextFloat());
//随机生成false或者true
System.out.println(rand.nextBoolean());
}
}
14、File类
java.io.File类代表文件和目录,在开发中进行文件操作时会用到本类
import java.io.File;
import java.util.Date;
public class Test {
public static void main(String[] args) throws Exception {
System.out.println(System.getProperty("user.dir")); //user.dir指本项目的目录
File f = new File("a.txt"); //相对路径:默认放到user.dir目录下面
boolean flag = f.createNewFile();//创建文件,flag判断是否成功
//检查文件相关信息
System.out.println("File是否存在:" + f.exists());
System.out.println("File是否是目录:" + f.isDirectory());
System.out.println("File是否是文件:" + f.isFile());
System.out.println("File最后修改时间:" + new Date(f.lastModified()));
System.out.println("File的大小:" + f.length());
System.out.println("File的文件名:" + f.getName());
System.out.println("File的目录路径:" + f.getPath());
flag = f.renameTo(new File("readme.txt")); //文件重命名
flag = f.delete(); // 将该文件删除
File f2 = new File("d:/电影/华语");
flag = f2.mkdir(); //mkdir只能创建单个目录,中间目录缺失则创建失败
System.out.println(flag);//创建失败
flag = f2.mkdirs(); //mkdir能创建多个目录,中间目录缺失则补充创建
System.out.println(flag);//创建成功
}
} 以树状结构展示目录树(递归算法) import java.io.File;
public class Test {
public static void main(String[] args) {
File f = new File("d:/电影");
printFile(f, 0);
}
static void printFile(File file, int level) {
//每有一层打印一个“-”
for (int i = 0; i < level; i++) {
System.out.print("-");
}
//输出文件名
System.out.println(file.getName());
//如果file是目录,则获取子文件列表,并对每个子文件进行相同的操作
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File temp : files) {
printFile(temp, level + 1); //递归调用
}
}
}
}
15、枚举类型
import java.util.Random;
public class Test {
public static void main(String[] args) {
// 枚举的遍历
for (Season k : Season.values()) {
System.out.println(k);
}
// switch语句中使用枚举
int a = new Random().nextInt(4); // 生成0,1,2,3的随机数
switch (Season.values()[a]) {
case SPRING:
System.out.println("春天");
break;
case SUMMER:
System.out.println("夏天");
break;
case AUTUMN:
System.out.println("秋天");
break;
case WINTER:
System.out.println("冬天");
break;
}
}
}
//季节枚举
enum Season {
SPRING, SUMMER, AUTUMN, WINTER
}
枚举体用于放置一些常量,隐性继承自 java.lang.Enum尽量不要使用枚举的高级特性,其高级特性都可以使用普通类来实现



