[Java][국비교육] Day 18

Ga02·2023년 1월 19일

국비교육

목록 보기
17/82

🔍 프로그램의 개발 오류(에러)

➰ 컴파일 타임 에러, Compile-time Error

컴파일 시점에 발생하는 에러로, 주로 문법 에러(Syntax Error) 👉🏻 컴파일러가 별도로 관리

  • 이클립스에서는 소스코드를 저장했을 때 즉시 확인할 수 있음

➰ 런타임 에러, Runtime Error

프로그램을 실행하는 도중에 발생하는 에러로, 수행할 수 없는 작업을 시도했을 때 발생
👀 Example

Object obj = null;
obj.toString();

➰ 논리 에러

프로그램이 에러없이 정상적으로 실행 또는 정상동작인 것처럼 보이지만 개발자가 의도한대로 프로그램이 동작하고있지 않은 상황 👉🏻 ex) 무한루프


🔍 Throwable 클래스

런타임 에러 상황을 정의하고 있는 클래스들의 최상위 부모 클래스
💡 런타임 에러를 정의! 컴파일 에러는 비교적 가벼운 문법 에러

  • Error클래스, Exception클래스를 자식클래스로 가짐

➰ Error 클래스, 에러

정상적인 상황으로 복구가 안되는 심각한 수준의 문제상황 👉🏻 프로그램 코드(자체적인 방법)로 해결할 수 없는 수준
👀 Example
OutOfMemoryError ➡ 메모리 가용용량이 부족한 상태에서 할당을 시도한 상황

➰ Exception 클래스, 예외

프로그램이 실행되는 동안 발생하는 예외적인 상황들을 정의하는 클래스 👉🏻 예외상황을 예측해서 프로그램 코드로 처리가능한 수준의 런타임 오류

  • try-catch 구문을 이용하여 미리 예외처리 작업을 추가
  • Checked Exception : RuntimeException의 하위클래스가 아닌 클래스들을 포함하는 Exception클래스의 자식 클래스
    • try-catch 구문을 이용한 예외처리가 반드시 필요 👉🏻 적용하지 않으면 문법에러 발생
    • 실행 전 코드 작성단계에서 미리 체크해서 예외처리 해야하는 상황들을 정의해 놓음 Unhandeld Exception
  • Unchecked Exception : RuntimeException클래스의 하위클래스
    • 예외처리구문을 반드시 작성하진 않아도 됨 👉🏻 컴파일 에러 발생하지 않음
  • Checked ExceptionUnchecked Exception는 미리 예외처리를 하느냐의 차이이지 예외가 발생하면 반드시 그에 대한 처리를 해야 함

🔍 예외처리, Exception Handling

발생할 수도 있는 예외적인 상황을 미리 대비하는 코드를 작성

➰ 예외처리 구문

프로그램 실행 중 예외상황이 발생하면 프로그램이 종료, JVM이 에러상황을 Exception클래스로 Throw해줌

  • 던져진 Exception 객체를 관리하면서 프로그램이 종료되지 않고 정상적인 흐름으로 되돌아가도록 예외처리 구문을 사용하여 예외처리 할 수 있음 👉🏻 try-catch 구문

➰ try-catch 구문

  • catch블록 구문을 여러개 작성할 수 있음
try {
	//try블록

	//예외가 발생할 수도 있는 코드를 작성하는 영역
	//예외 발생이 예측되는 코드

} catch( Exception e ) { //<- try 블록에서 발생한 예외 객체를 저장할 수 있는 변수 선언
	//catch 블록
	
	//프로그램이 종료되지 않고 실행할 코드를 작성하는 영역
	//예외처리 수행코드를 작성
	//예외정보 객체 e 변수를 사용할 수 있음
	//e.printStackTrace(); 코드만 적어두는 경우가 많음

} finally {
	//finally 블록

	//try 블록에서 예외가 발생해도, 발생하지 않아도 무조건 실행해야만 하는 코드를 작성하는 영역
	//finally블록 생략 가능
}
-------------------------------------------------------------------------------------
int[] arr = new int[5];

int i=0;
try {
    while(true) {
        arr[i] = i+1;

        i++;
    }
} catch ( ArrayIndexOutOfBoundsException e ) {
    //발생한 예외상황 출력
   e.printStackTrace();

} catch ( NullPointerException e ) {


} catch ( Exception e ) {
	//위의 두 예외가 아닌 나머지 예외 발생시 예외처리할 코드 작성

} finally {
	System.out.println("예외처리 후 실행");
}

➰ Multi catch, 다중 예외처리

하나의 catch 구문에서 예외 클래스를 여러개 적용하는 문법

try {

} catch ( NullPointerException | ArrayIndexOutOfBoundsException | NegativeArraySizeException e ) {
	
	//위 셋 예외상황 처리하는 구문
} catch ( Exception e ) { 
	
	//나머지 예외상황 처리하는 구문
}
-------------------------------------------------------------------------------
try {

} catch ( NullPointerException 
			| ArrayIndexOutOfBoundsException 
            | NegativeArraySizeException e ) {

	//위 셋 예외상황 처리하는 구문
} catch ( Exception e ) { 
	
	//나머지 예외상황 처리하는 구문
}

🔍 throw 키워드

예외상황을 발생시키기 위해 개발자가 직접 사용하는 코드

  • 객체는 정보값을 전달하고 throw는 예외를 맞히는 역할 👉🏻 throw에 예외 인스턴스를 넣으면 예외정보를 적어서 던져줌
    ✔ 예외객체를 생성(new)한다고 해서 예외를 발생(throw)시키는 것은 아님 👉🏻 객체를 생성해도 throw를 사용하지 않으면 예외발생x
  • 예외가 생성된 위치와 발생된 위치를 일치시키는 것이 좋음
String str = null;

if( str != null ) {

	//null이 아니라면 문자열 길이 출력
	System.out.println("str.length()); //str의 값이 null이므로 길이를 낼 수 없음 ➡ Dead Code
} else {

	//null이라면 예외객체를 직접 만들어서 예외상황 발생시킴 👉🏻 예외 발생시 프로그램 여기서 종료
    throw new NullPointerException();
}
------------------------------------------------------------------
//IOException ie = new IOException(); 👉🏻 throw와 위치가 다름

try {
	//throw ie;
    throw new IOException(); 👉🏻 throw와 예외 생성 위치 맞춰주기

} catch (IOException e) {

	e.printStackTrace();
}

🔍 throws 키워드

예외가 발생한 메소드에서 직접 예외처리를 하지 않고 자신을 호출한 메소드에게 예외처리를 미루는 키워드

  • 예외가 발생한 상황에 대한 책임을 Caller에게 묻는 것
    Caller : 메소드를 호출한 쪽의 메소드
    Callee : 호출당한 메소드
    👉🏻 Caller 메소드가 Callee 메소드를 call 함
    💡 main() 메소드에는 throws를 적용하지 않는 것이 좋음 ➡ 문법적으로는 가능하지만 사실상 코드를 버리겠다는 뜻
class Test {
	
    //unchecked Exception
	public void method() throws NullPointerException {
    	throw new NullPointerException();
    }
    
    //checked Exception
    public void method2() throws IOException {
    	throw new IOException();
    }

}
-----------------------------------------------------------------------
public class Exception_Test {
	public static void main(String[] args) {
    	
        Test tt = new Test();
        
        tt.method();
        👉🏻 unchecked exception이라서 try-catch 에러 안뜸
        
        try {
        	tt.method2();
    	} catch (IOException e) {
        	e.printStackTrace();
        }
    	👉🏻 checked exception이라서 try-catch 필수
    
    }

}

🔍 스트림, Stream

입출력장치와 프로그램 사이에 데이터를 통신(교환)할 수 있도록 만들어진 SW적인 장치 👉🏻 데이터 스트림, 데이터의 통로, 흐름

  • 입출력, Inout/Output, IO : 프로그램이 입출력장치와 데이터를 송/수신하는 것
  • 단방향 통신을 함
    • 입력장치 ➡ 입력스트림 ➡ 프로그램
    • 프로그램 ➡ 출력스트림 ➡ 출력장치
  • 버퍼(Buffer)를 가지고 있음
  • 기본적으로 바이트 단위로 통신
  • FIFO 구조로 데이터가 전달됨
    FIFO : First In First Out, 선입선출 ➡ 보통 데이터를 다룰 때 많이 사용됨 / Queue(대기열) ◀▶ FILO, LIFO
    FILO : First In Last Out, 선입 후출 ➡ Stack영역

    키보드 입력 ➡read()➡ 프로그램(byte[]) 저장 ➡write(), flush()➡ 모니터 출력

➰ 스트림의 분류

  • 입출력 구분
    • 입력 스트림 - InputStream, Reader
    • 출력 스트림 - OutputStream, Writer
  • 연결대상을 기준으로 구분
    • 1차 스트림 - 입출력장치와 직접 연결되는 스트림 ➡ System.in : 키보드 입력(기본 입력)
    • 2차 스트림 - 1차 스트림과 연결되어 추가기능을 제공하는 스트림 ➡ Scanner : 키보드로 입력된 데이터 스캔 후 데이터 타입 인식
  • 전송 데이터의 형태에 따른 구분
    • 바이트 스트림 - 바이트(1B) 단위로 통신하는 스트림 ➡ InputStream OutputStream
    • 문자 스트림 - 문자(char, 2B) 단위로 통신하는 스트림 ➡ Reader Writer
  • 기능에 따른 분류
    • 보조 스트림 - 다른 스트림을 보조하는 스트림

➰ InputStream 클래스의 read() 메소드

java.io.InputStream : 입력스트림의 기본 클래스

public int read(byte[] b) throws IOException {

}
  • 입력 스트림에서 매개변수 b 배열의 길이만큼 데이터를 읽어들임 👉🏻 한번에 최대로 읽어들일 수 있는 데이터의 크기는 b 배열의 길이
  • 읽어들인 데이터를 b 배열에 저장, 데이터의 길이(개수)를 int형으로 반환
  • 더이상 읽어들일 데이터가 없을 경우 -1을 반환
    👉🏻 End Of Stream : 읽어들일 데이터가 없는 상황, 데이터 스트림의 끝 (==EOF, End Of File)
    ➡ 키보드 스트림의 EOS : ctrl + z
InputStream is = System.in; //키보드 표준 입력 스트림객체
byte[] buf = new byte[1024]; //입력받은 데이터의 저장소 역할 👉🏻 read()메소드의 매개변수로 이용됨
int len = -1; //입력된 데이터의 길이 👉🏻 read()메소드의 반환값으로 이용
StringBuilder sb = new StringBuilder(); //입력받은 전체 문자열을 저장할 객체
int total = 0; //입력받은 문자열의 길이

try {
	System.out.println("<<입력 대기중>>");
    
    while( (len = is.read(buf)) != -1 ) {
    	
        String data = new String(buf, 0, len); //입력받은 byte[] 데이터를 String으로 변환
        sb.append(data) //변환된 문자열을 저장
        total += len;
        
        //👈🏻 예외가 없을 때 read()의 사용이 끝나는 시점 ➡ 예외가 있으면 try를 통과하므로 안전하게 finally에 넣기
    }

} catch ( IOException ) {
	e.printStackTrace();
} fainally { //read()의 사용을 끝내는 시점

	try{
    	//스트림 닫기
    	if(is!=null) is.close(); //키보드가 연결되어있다면 입력을 종료한다.
        //[InputStream is = System.in;] 입력을 뜻하는 것이 아니라 키보드가 연결된 그 자체 ➡ is!=null의 의미 : 키보드가 연결되지 않은 경우 / is=null이라면 키보드가 연결된 상태
    } catch ( IOException ) {
    	e.printStackTrace();
    }

}

➰ OutputStream 클래스의 write() 메소드

java.io.OutputStream : 출력스트림의 기본 클래스

public void write(byte[] b, int off, int len) throws IOException {

}
  • b 배열off 인덱스부터 시작해서 len 길이만큼 출력스트림으로 출력
  • writr() 메소드의 출력결과가 출력버퍼로 전송됨 👉🏻 출력장치로 곧바로 출력되지 않음
OutputStream os = System.out; //모니터 표준 출력 스트림 객체
byte[] buf = new byte[1024];
int len = 0; //출력할 데이터의 길이

buf[len++] = 'A';
buf[len++] = 'p';
buf[len++] = 'p';
buf[len++] = 'l';
buf[len++] = 'e';
buf[len++] = '\n';


try {
	os.write(buf, 0, len);
    os.flush();

} catch (IOException e) {
	e.printSteackTrace();
} finally {

	try{
		if(os!=null) os.close();
	} catch (IOExcption e) {
    	e.printStackTrace();
    }
}

➰ OutputStream 클래스의 flush() 메소드

출력버퍼에 담긴 출력 데이터를 강제로 출력 장치로 내보냄 👉🏻 write() 메소드 호출 후 flush() 메소드를 호출해주는 것이 좋음

public void flush() throws IOException {

}
profile
IT꿈나무 댓츠미

0개의 댓글