
📌 in - read : 파일을 읽는 기능
📌 out - write : 파일을 작성하는 기능
📌 예외와 에러는 다른개념임.
에러 : 개발자가 손 쓸 수 없는 것.
예외 : 개발자가 고칠수 있는 것.
👉 컴파일러쪽에서 예외처리를 해주는것 / checkedExcetion
👉 컴파일러쪽에서 예외처리를 안해주는것 / UncheckedExcetion
2-1. Checked Exception (검사예외)
👉 Exception 클래스의 서브 클래스중에서 RuntimeException 클래스를 상속하지 않는 예외
👉 try-catch문을 이용하거나, throws를 이용한 예외처리를 필수적으로 진행해줘야함.
👉 대표적인 Exception - IOException, ClassNotFoundException 등
2-2. UnChecked Exception (비검사 예외)
👉 Exception 클래스의 서브 클래스중에서 RuntimeException 클래스를 상속하는 클래스
👉 명시적으로 예외처리를 해주지 않아도 됨.
👉 대표적인 Exception - NullPointerException 등
1. try : 코드에서 문제가 발생 할 것 같은 부분을 try에 넣어서 오류가 발생하나 확인하는 란.
2. catch : try에서 발생한 오류를 어떻게 처리할지 작성하는 란
3. finally : try에서 오류가 발생하든 안하든 무조건 실행이 되어야하는 란.
4. 예외가 발생하면 해당 메소드에서 직접 처리함.
1. 나를 호출한 쪽에서 알 수 있게 한다.
2. 예외가 발생한 메소드를 호출 한 곳으로 예외 객체를 넘길수 있다.
3. throws는 어떠한 메소드의 내부 소스코드에서 에러가 발생했을때,
예외처리를 try-catch로 하는것이 아닌, 메소드를 사용한 곳으로 책임 전가 하는것.
FileInputStream fis = new FileInputStream("다운로드.jpg"); // 기본적인 사용방법
InputStream fis = new FileInputStream("다운로드.jpg");
//FileInput은 Input의 자식관계 이므로 fis의 데이터타입을 부모클래스로 변경해도 무관.
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("다운로드.jpg");
System.out.println(fis);
while(true){
int data = fis.read();//read에 대한 예외발생 //1byte씩 읽어 나간다
}
👆 <중요> 코드를 분석해보자
1. FileInputStream 객체를 사용하려면 예외가 발생하는데, 이 예외를 해결하기 위해선
FileNotFoundException을 사용해야한다.
2. read() 메소드를 사용하려면 예외가 발생하는데, 이 예외를 해결하기 위해선
IOException을 사용해야한다.
3. 두가지 예외처리의 부모를 사용하게 되면 한개의 예외처리로 해결되므로 Exception을 사용한다.
4. 하지만 무턱대고 Exception을 사용하면 badCode이다. 왜냐? 정확한 예외처리가를 해주지 않은것이기 때문이다.
public class Main {
public static void main(String[] args) throws Exception {
InputStream fis = new FileInputStream("다운로드.jpeg");
//기존에 저장해둔 사진 파일을 바이트 단위로 읽어준다
OutputStream fos = new FileOutputStream("다운로드2.jpeg");
//아래 읽고 쓰기를 진행하면 다운로드2라는 파일이 생성됨
System.out.println(fis);
while(true){
int data = fis.read();//사진의 1byte(한칸)씩 읽은것을 int값으로 반환
System.out.println(data); //해당 한칸씩 숫자로 출력한다
fos.write(data); //파일 쓰기
if(data == -1){ //read 메소드의 마지막은 -1 이므로
break;
}
}
👆 결국 어디서든 데이터를 읽고싶으면 InputStream을 사용하자.
👆 어디서든 데이터를 작성하고 싶으면 OutPutStream을 사용하자.
public class FileCopy1 {
// badcode
public void copy(String origin, String dest){
try{
InputStream in = new FileInputStream(origin);
OutputStream out = new FileOutputStream(dest);
while(true){
int data = in.read();//read에 대한 예외발생
out.write(data); //파일 쓰기
if(data == -1){
break;
}
}
}catch(Exception e){
e.printStackTrace(); //badcode
}//end catch
}
모든 자원을 연결한 뒤에는 close()하는 코드가 반드시 필요하다.
Scanner.close()처럼 닫아주는 역할을 해야하는데, 이 부분이
연결을 종료한다는 의미가 들어가 있기 때문에 gc에서 사용하지 않는다고 파악한다.
public class badcode {
// badcode
public void copy(String origin, String dest) {
try {
InputStream in = new FileInputStream(origin);
OutputStream out = new FileOutputStream(dest);
while (true) {
int data = in.read();//read에 대한 예외발생
out.write(data);
if (data == -1) {
break;
} //end if
}//end while
in.close(); //
out.close();
} catch (Exception e) {
e.printStackTrace(); //badcode
현재 try 내부에 close가 들어가있는데, try 윗 부분에서 문제가 발생한다면 바로 아래 catch부분으로 이동하기 때문에 close를 실행할 기회조차 없다.
try내부에 있는 in, out을 바깥쪽으로 빼서 유효범위에 문제가 되지 않도록 구조하고, finally 문 내에서
try - catch문을 하나 더 생성하는 방향으로 구조한다.
finally {
try{
in.close();
out.close();
}catch(Exception e){
현재 finally내부에 try-catch문을 작성하였는데, 만약 in.close에서 문제가 생겼을때, out.close가 실행되지 않는다.
}finally {
if(in != null){
try{ in.close();} catch(Exception e){}
}
if(out != null){
try{ out.close();} catch(Exception e){}
}
}//end finally
finally 내부에 try-catch문을 2개 만들어서 별도로 진행되도록 구조한다. 그렇게 된다면 in에서 오류가 발생하더라도 out은 그대로 진행되기 때문이다.
close뒤에 catch문에 대한 방법이 없는 이유는 close이후 에러가 발생하는것은 개발자 입장에서 고칠수 없는 에러이기 때문이다.
try( //close
InputStream in = new FileInputStream(origin);
OutputStream out = new FileOutputStream(dest);
) {
while (true) {
int data = in.read();//read에 대한 예외발생
try-with-resoures는 close를 진행해야하는 코드를 아래 finally에서 별도로 생성하지 않아도 try문 안에 close를 해야하는 문장들을 작성해두면 close까지 실행해준다.
📌 결국에 예외를 던진다 -> 문제가 생겼을때 의사소통을(상대가 알도록)하는것.
📌 코드를 설계할때 update에 관련된 메소드를 작성하는데 사용자가 사용중 80%-90%는 대부분 완료되는데, 10%경우에 안될때는 void를 사용하고 예외처리를 진행해라.
📌 정상과 비정상을 나눌땐 return값이 아닌 예외처리를 하자.
📌 메소드를 짤때는 throws와 close를 고민하자.
a. 가게가 문을 열어야 한다.
👉 문 : 포트번호, 가게를 연다 : 서버소켓을 생성
b. 가게가 손님을 기다린다.
👉 listener
c. 손님에게 원하는 결과를 제공한다.
👉 input output
public static void main(String[] args) throws Exception {
//bad code
ServerSocket serverSocket = new ServerSocket(5555);
System.out.println("Ready.........................");
//서버가 실행되는지 확인
Socket client = serverSocket.accept();
//네트워크로 이동하는 소켓 생성, 문을열어놓고 기다리는중.
System.out.println(client);
👆 현재 코드는 서버에 대한 코드이다. 서버의 입장으로 5555번포트를 열어두면 사용자는 URL에 127.0.0.1:5555 을 입력하여 접속하게 된다. 그렇게 접속을 할 때 소켓이 생성이 되고, 여기서 소켓은 종이컵 전화기라고 생각하면 쉽다.
📌 클라이언트에서 outputStream을 소켓을 통해서 write 작성한다.
📌 server에서 inputStream을 소켓을 통해서 read 한다.