1. 예외 처리
: 프로그램이 런타임에 중단되는 것을 예방하기 위한 코드.
- 자바에서 예외가 발생하면, 자바 시스템은 예외가 발생한 프로그램에게 예외 객체를 던진다.
-- 프로그램은 예외 객체를 맞으면 프로세스(실행중인 프로그램)는 죽는다. (기본 동작) --- 피구처럼!
1-1. try-catch
--- 발생한 예외객체를 try-catch 블록으로 잡아 프로그램이 죽지 않고 예외를 처리할 수 있도록 하는 방법 => 예외처리
(예외를 실제로 처리하는 경우보다 문제 발생을 개발자에게 알려서 수정할 수 있도록 하는 것이 대부분.)
try {
예외발생이 예상되는 or 강제 예외처리 요구 코드
} catch(예외 객체1) {
예외처리코드
} catch(예외 객체2) {
예외처리코드
} catch(Exception e) { // 모든 예외 받음. 맨 끝에 둬라.
예외처리코드
} finally {
// 정상실행, 예외처리, 예외처리안됨.. 등 어느 케이스에나 상관 없이 무조건 실행되는 블록.
// 있어도 되고 없어도 예외처리 실행됨.
// 사용했었던 자원 해제 코드.
}
- catch 블록은 try블록에서 발생한 예외객체와 타입이 같아야 그 예외 객체를 받아서 처리할 수 있다. (타입이 다르면 못 받음)
그러므로 예외객체가 여러개일 때에는 catch 블록은 타입별로 여러개 작성이 가능하다.
- 모든 예외 객체는 Exception 객체를 상속받는다.
=> 맨 끝에 catch(Exception e) {} 업캐스팅해 모든 예외를 받을 수 있게 함.
- try 블록 안의 코드가 순차적으로 실행되다가 예외 상황을 만나면 그 밑의 코드는 실행되지 않음.
--- 그래도 catch 블록에서 예외 처리를 다 해줘야 함!!
==> 그래야 try-catch 블록 밖의 코드가 전부 정상실행 됨!!!
▽ 예시 1
System.out.println("프로그램 시작");
try {
String s = null;
s.charAt(0); // 객체를 생성하지 않고 값을 호출함. -> NullPointerException
int x = 3 / 0; // 0으로 나눌 수 없음. -> ArithmeticException
} catch (ArithmeticException e) {
e.printStackTrace(); // 예외메시지 상세 출력
} catch (NullPointerException e) {
e.printStackTrace();
}
System.out.println("프로그램 종료");
=====================================
프로그램 시작
java.lang.NullPointerException: Cannot invoke "String.charAt(int)" because "s" is null
at 예외처리.Ex1.main(Ex1.java:11)
프로그램 종료
▽ 예시 2
int[] arr = { 1, 2, 3 };
String s = null;
try {
System.out.println("실행 1");
for (int i = 0; i < arr.length + 1; i++) {
System.out.println(arr[i]); // 예외 발생하면 try 실행 중단.
}
// 건너뜀. -> 다른 try-catch문으로 묶어줘야 실행됨.
System.out.println("실행 2");
s.charAt(0);
System.out.println("실행 3");
} catch (NullPointerException e) {
System.out.println(e);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println(e);
} catch (Exception e) {
System.out.println(e);
} finally {
System.out.println("무조건 실행되는 finally 블록");
}
====================================
실행 1
1
2
3
java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
무조건 실행되는 finally 블록
1-2. throws
: 예외 처리 미루기
- 이 메서드를 호출하는 쪽에서 예외처리를 하도록 미룸.
▽ 예시
package 예외처리;
import java.io.IOException;
class Test {
// 이 메서드를 호출하는 쪽으로 IOException 예외처리 미룸.
public void f1() throws IOException {
int ch = System.in.read();
}
}
public class 예외처리미루기 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Test t = new Test();
try {
t.f1();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
1-3. throw
: 예외 발생시킴. 예외객체 직접 던짐.
- 내 프로그램에서 문제가 될 만한 상황이라고 판단될 경우 강제로 예외 발생시킴.
throw 예외객체;
▽ 예시
package 예외처리;
class Test2 {
private int[] data;
private int cnt;
public Test2() {
data = new int[3];
}
public void add(int x) throws Exception {
if (cnt == data.length) {
throw new Exception("배열 참"); // 배열이 찰 경우 강제로 예외 발생
// 예외 객체 생성시 생성자에 파라메터로 문자열을 넣으면 예외 메시지로 사용됨.
}
data[cnt++] = x;
}
public void printArr() {
for (int i = 0; i < cnt; i++) {
System.out.println(data[i]);
}
}
}
public class 예외던지기 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Test2 t = new Test2();
for (int i = 0; i < 4; i++) {
try {
t.add(i);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
t.printArr();
}
}
=================================
java.lang.Exception: 배열 참
at 예외처리.Test2.add(예외던지기.java:13)
at 예외처리.예외던지기.main(예외던지기.java:32)
0
1
2
1-4. 사용자정의 예외 클래스
▽ 예시
- throw 예시에서
MyException 클래스 따로 생성하고
Exception 을 MyException 으로 바꿈.
결과는 같게 출력.
package 예외처리;
// 사용자 정의 예외 클래스는 Exception을 상속받아 정의
class MyException extends Exception {
public MyException() {
}
// 생성자 파라메터로 받은 문자열을 상위 클래스 생성자에 전달.
public MyException(String s) {
super(s);
}
}
class Test2 {
private int[] data;
private int cnt;
public Test2() {
data = new int[3];
}
public void add(int x) throws MyException {
if (cnt == data.length) {
throw new MyException("배열 참");
}
data[cnt++] = x;
}
public void printArr() {
for (int i = 0; i < cnt; i++) {
System.out.println(data[i]);
}
}
}
public class 예외던지기 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Test2 t = new Test2();
for (int i = 0; i < 4; i++) {
try {
t.add(i);
} catch (MyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
t.printArr();
}
}
==============================
예외처리.MyException: 배열 참
at 예외처리.Test2.add(예외던지기.java:23)
at 예외처리.예외던지기.main(예외던지기.java:42)
0
1
2
2. 입출력 스트림
* 입력 스트림: 밖에서 프로그램 쪽으로 데이터의 흐름을 소프트웨어로 구현한 모듈
* 출력 스트림: 프로그램에서 밖으로 데이터의 흐름을 소프트웨어로 구현한 모듈
프로그램 | ◀ | 입력 장치 |
▶ | 출력 장치 |
※ 표준 입출력
System.in // 표준 입력 (ex) System.in.read(): 키보드 입력
System.out // 표준 출력 (ex) System.out.println(): 콘솔 출력
System.err // 표준 에러
2-1. 자바스트림
- 입력 스트림 / 출력 스트림-- 양방향X
● 바이트 스트림: 한 바이트씩 읽고 씀 ---> 한글 깨짐. 영어 안깨짐.
(상속받음)
InputSteam: FileInputSteam (파일에서 1B씩 읽는 스트림)
º int read(): 1B 읽어서 int 타입으로 반환
º int read(byte[]): 파라메터로 넣은 배열 크기만큼 읽어서 배열에 저장. 읽은 바이트 수를 반환.
º int read(byte[], offs, size): size 만큼 읽어서 배열에 저장. 저장 시작 위치를 offs으로. 읽은 바이트 수를 반환.
OutputSteam: FileOutputSteam (파일에서 1B씩 출력하는 스트림)
º void write(int ch): 1B(ch) 출력
º void write(byte[]): 배열 크기만큼 배열 요소들을 출력. 출력한 바이트 수 반환.
º void write(byte[], off, size): byte[] 배열에서 offs위치부터 size 크기만큼 출력. 출력한 바이트 수 반환.
● 문자 스트림: 한 문자씩(2B) 읽고 씀
(상속받음)
Reader: FileIReader (파일에서 2B씩 읽는 스트림)
º int read(): 2B 읽어서 int 타입으로 반환
º int read(char[]): 파라메터로 넣은 배열 크기만큼 읽어서 배열에 저장. 읽은 문자 수를 반환.
º int read(char[], offs, size): size 만큼 읽어서 배열에 저장. 저장 시작 위치를 offs으로. 읽은 문자 수를 반환.
Writer: FileIWriter (파일에서 2B씩 출력하는 스트림)
º void write(int ch): 문자 1개 출력
º void write(char[]): 배열 크기만큼 배열 요소들을 출력. 출력한 문자 수 반환.
º void write(char[], off, size): char[] 배열에서 offs위치부터 size 크기만큼 출력. 출력한 문자 수 반환.
º writer(String str): 문자열 출력
▽ 바이트스트림-InputSteam-int read() 예시
package 입출력스트림;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
// FileInputStream 객체 생성
// 생성자에 읽을 파일의 경로
// 생성자에 지정한 경로의 파일에서 한 바이트씩 읽을 수 있는 스트림 생성
FileInputStream fi = new FileInputStream("src/입출력스트림/files/a.txt");
int ch;
while ((ch = fi.read()) != -1) { // EOF(End Of File): -1
System.out.print((char) ch);
}
fi.close(); //스트림 닫음
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
----------------------------------
▽ 바이트스트림-InputSteam-int read(byte[]) 예시
try {
// 사용할 inputsteam 생성
FileInputStream fi = new FileInputStream("src/입출력스트림/files/a.txt");
byte[] bbb = new byte[10]; // 10바이트 단위로 읽음.
int size = 0;
// 읽은 바이트 수가 0보다 크면 한 바이트라도 읽은 것므로 출력.
// (size = fi.read(bbb) == bbb.length) 하면,
// 10바이트씩 읽다가 마지막 부분에서 10 미만으로 읽혀서 출력이 되지 않음. 그래서 >0 으로 바꾼 것임.
while ((size = fi.read(bbb)) > 0) {
System.out.print(new String(bbb));
// Arrays.fill(): 배열을 지정한 값으로 채움.
Arrays.fill(bbb, (byte) ' '); // 배열 bbb를 ' '로 초기화
}
fi.close(); //스트림 닫음
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
----------------------------------
▽ 바이트스트림-OutputSteam-void write(int ch) / int write(byte[]) 예시
package 입출력스트림;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
// 1B씩 파일에 출력하는 스트림
// 쓰기용 파일은 있으면 그 파일에 덮어쓰기. 없으면 자동생성해서 씀. => 미리 만들 필요 X
// files 우클릭 -> Refrash
FileOutputStream fo = new FileOutputStream("src/입출력스트림/files/c.txt");
byte[] bbb = "hello java stream".getBytes(); // getBytes(): 문자열을 바이트 배열로 변환
// for (int i = 0; i < bbb.length; i++) {
// fo.write(bbb[i]);
// }
fo.write(bbb);
fo.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
----------------------------------
▽ 문자스트림-Reader-int read() / int read(char[])예시
package 입출력스트림;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
public class FileReaderTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
//FileReader: 파일에서 문자 단위로(2B)
FileReader fr = new FileReader("src/입출력스트림/files/a.txt");
// int ch;
// while((ch = fr.read()) != -1) {
// System.out.print((char) ch);
// }
char[] bbb = new char[10];
int size = 0;
while ((size = fr.read(bbb)) > 0) {
System.out.print(new String(bbb));
Arrays.fill(bbb,' ');
}
fr.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
----------------------------------
▼ 문자스트림 - 파일복사프로그램
package 입출력스트림;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Scanner;
class FileCopy {
// 파일 읽기 메서드. 파라메터로 읽을 파일의 경로를 받음
public String fileRead(String path) {
// StringBuilder: 문자열 조작을 빠르게 처리.
// 파일에서 읽은 내용을 저장.
StringBuilder sb = new StringBuilder();
try {
// 파일 읽기 스트림 생성
FileReader fr = new FileReader(path);
// 문자 100개씩 읽어서 담을 배열
char[] buf = new char[100];
while (fr.read(buf) > 0) { // read(): 읽은 문자 수 반환
sb.append(buf); // append(): StringBuilder에 문자열 끝에 추가
// (while 마지막 턴에 100개보다 적게 읽혔을 때 나머지는 쓰레기값으로 채워짐)
Arrays.fill(buf, ' '); // buf에 남은 쓰레기값 삭제
}
fr.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// toString(): StringBuilder 값을 String으로 변환
return sb.toString(); // 파일 전체 내용 반환
}
// 파일 복사 메서드. src: 원본파일경로, des: 복사파일경로
public void Copy(String src, String des) {
// 원본 파일 내용을 읽어서 txt에 저장.
String txt = fileRead(src);
try {
// 파일 출력 스트림 생성
FileWriter fw = new FileWriter(des);
// txt 전체를 한 번에 출력 스트림으로 출력
fw.write(txt);
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class 파일복사프로그램 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
// 파일들 저장된 디렉토리(폴더) 경로
String dir = "src/입출력스트림/files/";
// 원본 파일명 입력
System.out.println("원본 파일명: ");
String asdf = sc.next();
// File: 파일에 대한 정보. 파일의 존재 여부, 읽기, 쓰기, 실행 가능 등의 정보를 갖는다.
File f = new File(dir + asdf);
if (!f.exists()) { // exists(): 해당파일 존재 true, 아니면 false 반환.
System.out.println("원본 파일이 존재하지 않음");
return;
}
// 복사될 파일명 입력
System.out.println("복사 파일명: ");
String qwer = sc.next();
FileCopy fc = new FileCopy();
// 복사 메서드 실행
fc.Copy(dir + asdf, dir + qwer);
// 복사 파일 내용 읽음. -> 출력.
String res = fc.fileRead(dir + qwer);
System.out.println(res);
}
}
==========================================
원본 파일명:
a.txt
복사 파일명:
f.txt
afevas asdfgef
hhoiewf njhdf
안녕 안녕하세요
하하하 호호호 히히히
----------------------------------
● 1차 스트림(기본 스트림) (총)
: 단독 사용 가능
● 2차 스트림(보조 스트림) (소음기)
: 단독 사용 불가능. 꼭 기본 스트림에 연결해서 사용해야 함. => 기본 스트림 기능 추가
- 기본 스트림 + 보조 스트림 => 서로 타입이 맞아야 함. (읽기 끼리, 쓰기 끼리, 바이트 단위 끼리, 문자 단위 끼리 연결..)
* Buffered : 속도 빠르게 하는 보조스트림
º FileInputStream + BufferedInputStream
º FileOutputStream + BufferedOutputStream
º FileReader + BufferedReader
º FileWriter + BufferedWriter
▽ 바이트 스트림 + Buffered 예시
package 입출력스트림;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class BufferedStreamTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
// 기본 스트림
FileInputStream fi = new FileInputStream("src/입출력스트림/files/a.txt");
// 보조 스트림 -- 보조 스트림 생성자의 파라메터에 연결할 기본 스트림 객체 전달
BufferedInputStream bi = new BufferedInputStream(fi);
int ch;
while ((ch = bi.read()) != -1) {
System.out.print((char) ch);
}
bi.close(); // 보조 스트림 닫음
fi.close();
// 기본 스트림 생성
FileOutputStream fo = new FileOutputStream("src/입출력스트림/files/b.txt");
// 보조 스트림 생성.
BufferedOutputStream bo = new BufferedOutputStream(fo);
for (int i = 'a'; i <= 'z'; i++) {
bo.write(i);
}
bo.close();
fo.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
----------------------------------
▽ 문자 스트림 + Buffered 예시
package 입출력스트림;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedReaderWriterTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
FileReader fr = new FileReader("src/입출력스트림/files/a.txt");
BufferedReader br = new BufferedReader(fr);
int ch;
while ((ch = br.read()) != -1) {
System.out.print((char) ch);
}
br.close();
fr.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
FileWriter fw = new FileWriter("src/입출력스트림/files/b.txt");
BufferedWriter bw = new BufferedWriter(fw);
for (int i = 'A'; i <= 'Z'; i++) {
bw.write((char)i);
}
bw.close();
fw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
----------------------------------
* InputStreamReader / OutputStreamWriter: 바이트를 문자로 변환하는 보조스트림
- System.in: 표준입력. InputStream 하위객체. 1B씩 읽어서 한글 깨짐.
InputStreamReader 보조스트림을 연결해서 사용하면
==> 1B씩 읽은 것을 2B씩 묶어서 문자단위로 변환해줌 ==> 한글 안 깨짐.
InputStreamReader ir = new InputStreamReader(System.in);
▽ InputStreamReader 예시 -- 엔터 누르면 출력
package 입출력스트림2;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class InputStreamReaderTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int ch;
try { // 엔터 누를 때까지 입력받고 엔터 누르면 출력.
while ((ch = br.read()) != '\n') {
System.out.print((char)ch);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
----------------------------------
* ObjectInputStream / ObjectOutputStream: 객체 단위 읽는 보조 스트림
직렬화: 객체 전달시 참조값이 아닌 멤버변수 값을 하나씩 줄세워 전달하는 것.
자바는 객체를 전달할 때 참조값만 전달함. 때문에 네트워크를 통해 전달할 때 꼭 직렬화처리를 해서 전달해야 함
=> 구현: Serializable 인터페이스 상속받으면 됨.
▽ 직렬화 예시
package 입출력스트림2;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Member implements Serializable { // 직렬화 처리
String name;
String tel;
public Member(String name, String tel) {
this.name = name;
this.tel = tel;
}
@Override
public String toString() {
return "Member [name=" + name + ", tel=" + tel + "]";
}
}
public class ObjInputOutputStram {
public static void main(String[] args) {
// TODO Auto-generated method stub
Member m1 = new Member("aaa", "111");
Member m2 = null;// 파일에서 읽을 객체 저장할 변수
String path = "src/입출력스트림/files/data.dat";
// 출력스트림으로 시작할 거기 떄문에 미리 생성할 필요 없음(자동생성될거임)
try {
// 파일에 바이트 단위로 쓰는 스트림 생성
FileOutputStream fo = new FileOutputStream(path);
//위 기본 스트림에 객체 단위로 쓰는 보조스트림 생성해서 연결
ObjectOutputStream oo = new ObjectOutputStream(fo);
//writeObject(): 객체 한개 출력
oo.writeObject(m1);
//스트림 닫음
oo.close();
fo.close();
//파일에서 바이트 단위로 읽는 기본 스트림 생성
FileInputStream fi = new FileInputStream(path);
// 객체 단위로 읽는 보조스트림 생성해서 위 기본 스트림(fi)와 연결
ObjectInputStream oi = new ObjectInputStream(fi);
//readObject(): 객체 한개를 읽어서 Object 타입으로 반환. 다운캐스팅 필요.
m2 = (Member) oi.readObject();
System.out.println(m2);
oi.close();
fi.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
----------------------------------
* 랜덤 위치에서 읽거나 쓰기