java基礎--------IO輸入輸出之異常、File類和遞歸


第一部分 異常

異常按照情況的嚴重性,可以分爲Error和Exception。Error是比較嚴重的情況,比如內存溢出,不是寫程序本身的情況。Exception則又按照其出現的時間,分爲編譯期異常和運行期異常。運行期異常是:RuntimeException,非RuntimeException的異常都屬於編譯期異常。
運行期異常是代碼不夠嚴謹。


如果程序出現了問題,我們沒有做任何處理,最終JVM就會做出默認的處理。將異常的名稱,原因及出現的問題等信息輸出控制檯。同時會結束程序。雖然JVM給出了我們提示信息,但是其同時也結束了程序運行。這就導致程序不能執行完,爲了能夠將一些無關緊要或者局部問題排除掉,並且程序繼續執行,這個時候就需要自己處理,拋出異常。
處理異常兩種方式:
(一)、try...catch....finally
(二)、throws 拋出


前者的處理格式爲
try{
可能出現問題的代碼;
}catch(異常名 變量){
針對問題的處理;
}finally{
釋放資源;
}
注意:try裏面的問題越少越好。因爲這裏的代碼越多,需要處理的信息就會越多,JVM就要分配更多的資源來處理。

catch裏面必須有內容,哪怕是給出一個簡單的提示


第一種格式:


try{
...
}catch(異常類名 變量名){
...
}


try{
...
}catch(異常類名 變量名){
...
}
...


第二種格式:
try{
...
}catch(異常類名 變量名){
...
}catch(異常類名 變量名){
...
}


能明確的儘量明確異常類型,如果拋出Exception父類,父類就要再子類中逐一查詢。降低了效率。


第三種:jdk1.7之後出現

try{


}catch(異常名1|異常名2|異常名3 變量){
...
}
這裏需要注意的是異常名必須是平級關係。不能有父類如Exception。


編譯期異常與運行期異常的區別:
運行期異常:只要程序足夠嚴謹,就不會發生運行期異常。
編譯期異常:必須處理,否則無法運行。


異常中的方法:
public String getMessags(); 返回該消息的詳細信息字符串
public String toStrng():返回異常的簡單信息描述
printStackTrace()




(二)、throws:定義功能方法時,需要把出現的問題暴露出來讓調用者去處理。就是通過throws在方法上標示。


格式:throws 異常類名
這個格式必須跟在方法的括號後面。
當我們不想處理異常,或者沒有能力去處理這個異常的時候,就可以在方法聲明上將異常通過throws拋出。這樣在調用該方法時,調用者會來處理這個異常。如果調用者也不處理這個異常,而是將這個異常拋給了main方法,結果main方法就給了虛擬機,這樣就沒有意義了。因爲虛擬機會在遇到異常時,終止程序。最好能在被調用的時候將異常處理掉,避免在main方法上拋出異常。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo {
	public static void main(String[] args) {
		System.out.println("我要去");
		try {
			method();
		} catch (ParseException e) {
			e.printStackTrace();
		}
		System.out.println("有肉吃");
	}
	// 編譯期異常的拋出
	// 在方法聲明上拋出,是爲了告訴調用者,方法有問題
	public static void method() throws ParseException {
		String s = "2014-11-20";
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date d = sdf.parse(s);
		System.out.println(d);
	}
}




上面的這個例子在main方法中調用method();但是method()方法是有異常拋出的,如果調用者直接在main方法上直接拋異常,就會導致程序在運行到method()時就停止了。但是如果通過try..catch..來處理這個異常,最終程序還可以走到"有肉吃"。


注意:在調用方法時,如果方法聲明上有異常,調用者最好處理(編譯期異常)。但是如果這種異常是運行期異常,我們就可以不處理。


關鍵字:throw與throws的區別:
 throw:在功能方法內部出現某種情況,程序不能繼續運行,需要進行跳轉時,就用throw把異常對象拋出。只能拋出一個異常對象名,執行throw,則一定會拋出異常。throws用在方法聲明後面,跟的是異常類名,可以跟多個異常類名,用逗號隔開,throws表示出現異常的一種可能性,並不一定會發生。
public static void method(){
	int a=10;
	int b=0;
	if(b==0){
		throw new ArithmeticException();
	}else{
		System.out.println(a/b);
	}
}






finally:
被finally控制的語句體一定會執行。只要虛擬機不退出,就會執行。
public static void show(){
	int a=10;
	try{System.out.println(a/0);
	a=20;
}catch{
	a=30;
	return a;//走到這一步return 30;//又走回來,return 30.
}finally{
	a=40;//第二步此時a爲40
}
return a;
	
}






第二部分File類
文件和目錄路徑名的抽象表示形式。


File類的常用操作及演示


構造方法:
public File(String pathname) 根據一個路徑得到File對象
public File(String parent,String child)根據一個目錄和一個子文件得到一個對象
public File(File parent,String child) 根據一個父File對象和一個子文件/目錄得到File對象。
通過構造方法,我們可以建一個File類的對象,通過File類的對象,可調用其方法。


第一種File構造方法:


import java.io.File;
public class FileDemo{
	public static void main(String [] args){
		//創建一個對象file1,其指向e盤的it文件夾。
		File file1=new File("e:\\it");
		//在E盤創建一個文件夾,命名爲it;
		file1.mkdir();			
	}
}



第二種File構造方法


//創建一個對象file。
File file=new File("E:\\it","it.txt");
File file2=new File("e:\\it\\a.java");
//通過調用創建文件的方式創建文件。
file.createNewFile();
file2.createNewFile();
上面的第一種構造方法創建的對象,通過調用創建文件的方法,先是在E盤裏創建了一個名爲it的文件夾,然後又在該文件夾中創建了一個it.txt的文件。第二種構造方法創建的對象,調用createNewFile()方法時,在已經存在的it文件夾中又創建了一個a.java的文件。file2創建文件時,該目錄必須已經存在,不然就會報出,“系統找不到指定路徑”的異常。




創建功能
public boolean createNewFile()創建文件  拋異常的方法
public boolean mkdir()創建文件夾  不拋異常的方法
public boolean mkdirs())創建多層文件夾


如果要創建多層文件夾時,可以調用mkdirs()。
File file=new File("e\\it\\哈哈\\安卓");
file.mkdirs();
系統將會在e盤創建這樣一個多層文件夾。
如果在創建File對象時,沒有寫盤符,將會在當前文件夾中創建。


注意:
File file=new File("e\\哈哈\\a.txt");
file.mkdirs();
這裏將會在e盤創建一個哈哈文件夾,並且在該文件夾的裏面再創建一個名爲“a.txt”的文件夾。


刪除功能
public boolean delete()
例:File file=new File("e:\\it");
file.delete();
file.delete()方法將會刪除e盤中的it文件夾。








重命名功能
public boolean renameTo(File dest)


File file =new File("e:\\andriod.txt");
file.createNewFile();
File file2=new File("d:\\it.txt");
file.renameTo(file2);
如果兩個路徑相同,則是重命名如果兩個路徑不同,則是重命名並且剪切。上面這個例子,就是將E盤中的andriod.txt文件剪切到D盤根目錄下,並且重命名爲it.txt。


判斷功能:
public boolean isDirectory() 判斷是否爲目錄
public boolean isFile()判斷是否爲文件
public boolean exists() 判斷是否存在
public boolean canRead() 是否可讀
public boolean canWrite() 是否可寫
public boolean isHidden() 是否隱藏


獲取功能:
public String getAbsolutePath() 獲取絕對路徑
public String getPath()獲取相對路徑
public String getName()獲取文件名
public long length()獲取文件長度
public long lastModified()獲取最後一次修改毫秒值


高級獲取功能
public String[] list() 返回一個字符串數組,這些字符串指定此抽象路徑名錶示的目錄中的文件和目錄。
public File[] listFiles() 獲取指定目錄下的所有文件或者文件夾的File數組 


public static void main(String [] args){
	//將e盤目錄封裝成對象
	File file=new File("e:\\");
	//對象調用方法,並且返回給數組str;
	String [] str=file.list();
	for(String s:str){
	//將會把E盤根目錄下的文件及文件夾的名稱都輸出。
		System.out.println(s);
	}
}


導包運行上面的程序,我們就會發現其輸出了e盤根目錄下的所有內容,包括隱藏文件等。
另外還有一種方法也能達到這種效果
File [] array=file.listFiles();
for(File f:array){
	//由於f爲File類型,因此可以調用其方法getName()來獲取文件名。
	System.out.println(f.getName());
}


雖然上面兩種方法輸出結果一致,但是後者由於返回的是文件對象數據,因此其能夠調用更多的方法,用途也更廣泛。


注意:絕對路徑和相對路徑的區別,絕對路徑是從盤符開始直到文件名,但是相對路徑,則是在當前文件夾下的路徑。也就是相對路徑,加上當前文件夾的絕對路徑,纔是這個文件的絕對路徑。




練習題:輸出D盤根目錄下後綴名爲.txt的文件。


方法一:
import java.io.File;
class FileDemo{
	public static void main(String [] args){
		//將E盤根目錄轉爲對象
		File file=new File("e:\\");
		File [] array=file.listFiles();
		for(File f:fileArray){
			//判斷是否爲文件
			if(f.isFile()){
				//如果是文件,那麼它是不是以“.txt”結尾呢?
				if(f.getName().endsWith(".txt"){
					//滿足上面的條件,就是我們需要輸出的。
					System.out.println(f.getName());
				}
			}
		}
	}
}




方法二:這個方法區別於上面的本質在於不是先獲取所有元素,再判斷,而是在獲取的時候,已經是判斷過後滿足條件的啦。這裏就要用文件過濾器,其方法如下:
public String [] list(FilenameFilter filter) 這個返回的是String數組
public File [] listFiles(FilenameFilter filter) 返回的是File數組


import java.io.File;
class FileDemo{
	public static void main(String [] args){
		//封裝E盤目錄
		File file=new File("e:\\");
		//通過文件過濾器的匿名實現類對象來創建對象
		String [] str=file.list(new FilenameFilter(){
			//重寫方法
			public boolean accept(File dir,String name){
				//通過File的第三種構造方法,封裝目錄。
				File file =new File(dir,name);
				//判斷該文件名是不是文件
				boolean flag=file.isFile();
				//判斷該文件是不是以".txt"結尾
				boolean flag2=name.endsWith(".txt");
				return flag&&flag2;
			}
		});
		for(String s:str){	
			System.out.println(s);
		}
	}
}






第三部分 遞歸
定義:方法定義中調用方法本身的現象。(自己調自己,而不是別人調)。


注意:遞歸一定要有出口,不然就是死遞歸
遞歸的次數不能太多,否則就內存溢出
構造方法不能遞歸使用
5!=5*4*3*2*1;
5!=5^*4!

遞歸解決問題的思想:

遞歸方法在加載到棧內存後,由於方法本身調用方法,第一個進棧的遞歸,將在最下面,他的上面,由於是在不停地調用方法本身,將會形成一種鏈式結構,直到方法的最終參數值,這是方法的分解。


當到達方法的最終值時,方法就開始運算,然後逐層消失,直到回到最高層的遞歸方法。

練習題:

輸出斐波拉契數列:1,1,2,3,5,8,13.21,34,55

public class Test8 {	
		public static void main(String [] args){
			for(int x=1;x<21;x++){
				System.out.println(show(x));
			}	
			System.out.println("*********");			
				System.out.println(array(20));					
		}
		//數組實現
		public static int array(int n){
			int[] arr = new int[n];
			arr[0] = 1;
			arr[1] = 1;
			int s=2;
			// arr[2] = arr[0] + arr[1];
			// arr[3] = arr[1] + arr[2];
			// ...
			for (int x = 2; x < arr.length; x++) {
				arr[x] = arr[x - 2] + arr[x - 1];
				s=arr[x];
			}
			return s;			
		}
		//遞歸方法。不是if...else連用,還需要在方法體外面實現返回。
		public static int show(int n){	
			int s=2;
			if(n==1||n==2){
				return 1;
			} 
			
			if(n>2){					
				s= (show(n-2)+show(n-1));				
			}
				return s;
		}
		//遞歸方法。如果是if...else連用,就不用再在方法體外面return返回值了。
		public static int fib(int n) {
			if (n == 1 || n == 2) {
				return 1;
			} else {
				return fib(n - 1) + fib(n - 2);
			}
		}
		//for循環變量第一種
		public static int ForDemo(int n){
			if(n==1||n==2){
				return 1;
			}
			int a=1;
			int b=1;
			int c=2;
			for(int x=2;x<n;x++){
				c=a+b;
				a=b;
				b=c;
			}
			return c;
		}
		//for循環變量第二種
		public static int ForDemo1(int n){
			if(n==1||n==2){
				return 1;
			}
			int a=1;
			int b=1;			
			for(int x=2;x<n;x++){
				int temp=a;
				a=b;
				b=temp+b;
				
			}
			return b;
		}
		
}



輸出e盤下的所有.java文件的絕對路徑。
public static void main(String [] args){
	File file=new File("e:\\");
	getAlljava(file);
	
	
}
public static void getAlljava(File file){
	File [] fileArray=file.listFiles();
	for(File file1:fileArray){
		if(file1.isDirectory()){
			getAlljava(file1);
		}else{
			if(file1.getName().endsWith(".java")){
				System.out.println(file1.getAbsolutePath());
			}
		}
		
	}
	
}



刪除e盤下所有內容:
public static void main(String[] args) {
		// 封裝目錄
	File srcFolder = new File("demo");
		// 遞歸實現
	deleteFolder(srcFolder);
	}
private static void deleteFolder(File srcFolder) {
		// 獲取該目錄下的所有文件或者文件夾的File數組
	File[] fileArray = srcFolder.listFiles();
	if (fileArray != null) {
			// 遍歷該File數組,得到每一個File對象
		for (File file : fileArray) {
				// 判斷該File對象是否是文件夾
			if (file.isDirectory()) {
				deleteFolder(file);
			} else {
				System.out.println(file.getName() + "---" + file.delete());
			}
		}
		System.out.println(srcFolder.getName() + "---" + srcFolder.delete());
	}
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章