Java数组与异常
1.数组
数组的概念
概念:具有一组相同数据类型的数据结构。(理解为容器,就是装数据的)
相同数据类型
数据结构:在内存中是连续的内存空间。
数组的使用
使用:
创建数组
操作数据:存储数据,获取数据
数组中可以存储任意类型的数据,但是数组本身是引用类型的。
语法:
动态创建数组:创建和赋值分开写。
数组存储的数据类型[] 数组的名字 = new 数组存储的数据类型[长度];
数组定义格式详解:
数组存储的数据类型:创建的数组容器可以存储什么数据类型。
[]:表示数组
数组名字:为定义的数组起个变量名,满足标识符规范,可以使用名字操作数组。
new:关键字,创建数组使用的关键字。
数组存储的数据类型:创建的数组容器可以存储什么数据类型
[长度]:数组的长度,表示数组容器中可以存储多少个元素。
注意:创建数组时要指明数组的大小(长度,容量),然后在使用,数组有定长特性,长度一旦指定,不可更改。
int[] arr = new int[5]; //先创建数组
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
静态创建数组:创建数组和赋值写一起
数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3...};
数据类型[] 数组名 = {元素1,元素2,元素3...};
int[] arr = {1,2,3,4,5};
示例:
//double[] arr2 = new double[]{3,4,5,6,7};//只能放相同的数据类型
//静态初始化
double[] arr2 = {3.4,2.3,4.5};//数组的类型,数组的长度,每个下标对应的元素就都确定了
System.out.println("下标为2的值为:"+arr2[2]);
System.out.println("arr2数组的长度:"+arr2.length);
注意点:
数组只有一个名称,即标识符
元素索引标明了元素在数组中的位置,下标从0开始
数组中的每个元素都可以通过下标来访问
数组的长度固定不变,避免数组越界
数组变量属于引用类型
数组元素的默认值和成员变量的默认值一样
数组的遍历
方法1
普通for循环:
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
}
方法2
增强for循环:
语法:
for(type element : array){
System.out.println(element);
}
示例:
for(int e : arr){
System.out.println(e);
}
缺陷:遍历数组或集合时无法访问索引(下标)值
用途:一般用于遍历显示数组或集合中元素的内容。
增强for能不能给数组赋值?
int[] arr = {1,3,4};
int[] arr2 = new int[3];
int i = 0;
for(int e : arr){
//e = 10; //不可以直接赋值
arr2[i] = e;
i++;
}
for(int a : arr2){
System.out.println(a);
}
可变参数
一个方法中,参数的类型确定,但是数量不确定,就可以使用可变参数。
方法当中可变参数,就是数组。
语法:参数类型…参数名
调用:参数的数量:0~多个
public class ArrayDemo3 {
//求不确定个数int类型的数字的和
public static int getSum1(int a1,int a2){
return a1+a2;
}
//可变参数(求多个整数的和)
public static int getSum2(int... nums){
int sum = 0;
for (int e : nums){
sum += e;
}
return sum;
}
public static void main(String[] args) {
int sum = getSum1(3,4);
System.out.println("sum:"+sum);
int sum2 = getSum2(1,2,3,4,4);
System.out.println(sum2);
}
}
注意事项:
1.一个方法最多只能有一个可变参数
2.如果形参列表中,除了可变参数,还有其他的参数,可变参数要位于参数列表的末尾。
数组拷贝
浅拷贝:拷贝的是内存地址。
深拷贝:拷贝的是数值。
public class ArrayDemo4 {
public static void main(String[] args) {
/**
* 数组的拷贝
*/
int[] arr1 = {3,45,47,67,98};
int[] arr2 = arr1; //浅拷贝 拷贝的是内存地址
arr2[0] = 100;
System.out.println("arr1[0]:"+arr1[0]);
System.out.println("arr2[0]:"+arr2[0]);
System.out.println("---------------------------------");
//深拷贝,拷贝的是内容
int[] arr3 = new int[arr1.length];
for(int i = 0;i < arr3.length; i++){
int num = arr1[i];
arr3[i] = num;
}
arr3[0] = 30;
System.out.println("arr1[0]:"+arr1[0]);
System.out.println("arr3[0]:"+arr3[0]);
}
}
Arrays数组的工具类
常用方法:
binarySearch(数组,key)–>int,二分搜索。
sort(数组)–>void,排序
toString(数组)–>String,按照字符串打印数组中的内容
copyOf(原始数组,新数组长度)–>新数组,数组拷贝
equals(数组1,数组2)–>boolean
示例:
public class ArraysDemo5 {
public static void main(String[] args) {
//binarySearch(数组.key)-->int. 二分查找
int[] arr = {4,5,12,76,23};
//注意:搜索方法一定要先排序
//排序
Arrays.sort(arr);
//两种遍历方式
// for(int i = 0;i < arr.length;i++){
// System.out.println(i);
// }
System.out.println("arr:"+Arrays.toString(arr));
System.out.println("--------------");
int index = Arrays.binarySearch(arr, 5); //找到要查找的值所在的下标。
System.out.println(index);
//数组的拷贝
int[] newArr1 = Arrays.copyOf(arr, arr.length);
int[] newArr2 = Arrays.copyOf(arr, 7);//这种拷贝是深拷贝
System.out.println("newArr1:"+Arrays.toString(newArr1));
System.out.println("newArr2:"+Arrays.toString(newArr2));
System.out.println("--------------------------");
boolean equals1 = arr.equals(newArr1); //这个equals调用的是Object类的equals方法,比较的是内存地址
System.out.println("equals1:"+ equals1);
//比较数组的内容
boolean equals2 = Arrays.equals(arr,newArr1);
System.out.println("equals2:"+ equals2);
}
}
二维数组
一维数组:容器,存储了一组的数据,数据名配合下标获取到的就是元素数据了,也就是数值。
二维数组:容器,存储了一维的一维,二维数组中的元素,而是一堆数组。
public class ArraysDemo6 {
public static void main(String[] args) {
int[] arr = {5,4,2,15,45};
//二维数组里面的元素就是一维数组
//动态声明
int[][] arrEle = new int[3][4];//第一个长度为3,表示的这个二维数组存放了3个一维数组;第二个长度4:表示每一个一维数组存放多少个数字
arrEle[0][0] = 23;
arrEle[0][1] = 41;
System.out.println(arrEle); //二维数组的地址
System.out.println("arrEle[0]:"+arrEle[0]); //第一个一维数组的地址
System.out.println("arrEle[0][0]:"+arrEle[0][0]); //第一个一维数组的第一个元素
System.out.println("------------------------");
//静态初始化
int[][] newArr = {{2,3},{4,23},{98,54,123}}; //这个叫锯齿数组
//遍历
for(int i = 0; i <newArr.length; i++){
//先获取每一个一维数组
int[] ints = newArr[i];
//在遍历另一个一维数组
for(int j = 0;j < ints.length; j++){
int num = ints[i];
System.out.println("num:"+ num);
}
System.out.println("--------------------");
}
//
System.out.println("----^^^^^----");
for(int[] ints : newArr){
for(int num : ints){
System.out.println(num);
}
}
}
}
2.异常
概念
程序在运行的时候,发生的不正常事件,就是所谓的异常。
异常的分类
Throwable:可抛出的,一切错误或异常的父类,位于java.lang包中。
Error:JVM、硬件、执行逻辑错误,不能手动处理。
Exception:程序在运行和配置中产生的问题,可处理。
RuntimeException:运行时异常,可处理,可不处理
CheckedException:检查时异常,必须处理
示例:
public class ExceptionDemo {
public static void main(String[] args) {
//异常: 可以处理
int[] arr = {2,3,4,5};
System.out.println("arr[4]:"+arr[4]); //java.lang.ArrayIndexOutOfBoundsException: 4
//错误
int[] arr2 = new int[1024*1024*1024]; //java.lang.OutOfMemoryError: Java heap space
}
}
**检查异常:**由编译器能够检查出来的异常,外部原因导致的异常,程序中必须处理。
FileNotFoundException
IOException
SQLException
运行时异常:RuntimeException,也叫非检查异常,编译器不检查的异常。往往一些代码的逻辑问题。
NullPointerException
ArrayIndexOutOfBoundsException //数组越界
ClassCaseException
NumberFormatException
示例:
public class ExceptionDemo {
public static void main(String[] args) {
// //异常: 可以处理
// int[] arr = {2,3,4,5};
// System.out.println("arr[4]:"+arr[4]); //java.lang.ArrayIndexOutOfBoundsException: 4
//
// //错误
// int[] arr2 = new int[1024*1024*1024]; //java.lang.OutOfMemoryError: Java heap space
//异常,检查时异常和运行时异常
int div = 10/0; //java.lang.ArithmeticException: / by zero
//编译器能检查出来的,检查异常
// FileInputStream file = new FileInputStream("d:\\hello.txt");
}
}
异常产生和传递
异常的处理
捕获异常:try…catch…finally
语法规则:
try{
//可能产生异常的代码
}catch(异常类型1 e){
//捕获异常的处理
}catch(){
//捕获异常的处理
}finally{
//无论程序是否产生异常,此处的代码一定会被执行
//比如说:释放资源,
}
示例:
public class ExceptionDemo2 {
public static void main(String[] args) {
//异常,检查时异常和运行时异常
try {
int div = 10/0; //java.lang.ArithmeticException: / by zero
System.out.println("--------------");
} catch (Exception e){
e.printStackTrace();//追踪信息
System.out.println("捕获了异常。。。");
} finally {
System.out.println("finally语句块最后一定要执行!");
}
System.out.println("hello world!");
System.out.println("hello world!");
System.out.println("hello world!");
}
}
注意:
1.一个try可以匹配多个catch语句
2.如果try中产生了异常对象,那么会跳出try,进入相应的catch中处理异常,从上向下匹配。
3.如果是多个catch语句,那么小的异常捕获处理写前面,大的异常处理写后面。
4.finally是可选的。
声明异常throws
方法级别上,向外抛出异常。
方法的声明上就要通过throws关键字声明抛出异常。
public static void test1() throws NullPointerException{
}
[修饰符1,修饰符2...] 返回值类型/void 方法名(参数列表) 异常的声明{
}
按照方法的调用链反向传递,如果始终没有处理异常,最终会由JVM进行默认异常处理(打印堆栈跟踪信息)。
运行时异常的抛出,不一定要处理。
检查异常的抛出,必须处理。
重写时,子类不能抛出比父类更大的异常。
throw关键字
throw和throws的区别:
1.throws,用于定义方法的时候,声明该方法向外抛出异常。
2.throw,主动抛出一个异常的对象,打断程序的执行,配合try catch或者throws来使用
public class ThrowDemo {
public static int div(int x,int y) throws Exception{
if (y==0) {
throw new Exception("除数不能为0。");
}
System.out.println("kkkkkkkkk");
return x/y;
}
public static void main(String[] args) {
System.out.println("你好!!!");
System.out.println("你好!!!");
try {
div(10,0);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("你好!!!");
System.out.println("你好!!!");
}
}
自定义异常
需继承Exception或Exception子类,代表特定问题。
异常类型 望文生义,可在发生特定问题时抛出对应的异常。
常用构造方法
无参构造方法。
String message参数的构造方法。
public class AgeException extends RuntimeException{
public AgeException(String message) {
super(message);
}
}
public class Person {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
if(age < 0){
throw new AgeException("年龄参数值不合理.");
}
this.age = age;
}
}