예외처리
예외 처리(Exception Handling) 는 프로그램 실행 중에 발생할 수 있는 예외적인 상황을 적절하게 처리하기 위한 프로그래밍 기법입니다.
1. 예외 처리 메커니즘
- throw: 예외를 강제로 발생시키는 키워드입니다. 시스템 오류가 아닌 상황이더라도, 비즈니스로직이나 데이터 상의 오류상황을 강제로 발생시켜 예외를 강제로 생성합니다.
- throws: 메서드 선언 시 사용하여 해당 메서드 내에서 예외를 직접 처리하지 않고 호출자에게 예외 처리를 위임한다는 의미입니다. 이를 통해 메서드 사용자는 지정된 예외를 반드시 처리해야 합니다.
- try-catch : 던져진 exception을 해당 scope 내에서 코드로 받아서 처리를 진행함.
- try-catch-final : try catch 구문과 상관없이 마지막으로 finally 안의 구문은 반드시 실행시킴. 예외가 발생해서 throws를 한다고해도 처리를 할 것은 처리를 할 수 있도록 도와줌. 예를 들면 파일 연결끊기와 같은 자원정리라던지.
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("Exception caught: " + e.getMessage());
} finally {
System.out.println("This block is always executed.");
}
2. 예외의 분류
- Checked 예외: 컴파일 단계에서 반드시 처리해야 함을 확인시키는 예외들로, 일반적으로 예상 가능하고 처리 가능한 상황에서 사용됩니다. 코드 작성자가 throw exception을 하거나, 호출하는 method에서 throws하는 경우 코드 호출자는 throws 혹은 try-catch로 코드상에서 예외처리를 반드시 해야함.
- 예: IOException, FileNotFoundException, SQLException
- * 최근에는 checked exception을 선호하지 않고 unchecked excpetion으로 변환하여 throw 하는 추세임
class Parent {
void method() throws InterruptedException {
// ...
} }
class Child extends Parent {
@Override
void method() throws Exception {
// ...
} }
public class Test {
public static void main(String[] args) {
Parent p = new Child();
try {
p.method();
} catch (InterruptedException e) {
// InterruptedException 처리 하지만 그 외 예외는 놓치게 된다
}
}
- Unchecked 예외: 실행 시점(Runtime)에서 발생하며, 컴파일러가 강제로 예외 처리를 요구하지 않습니다. 주로 프로그램의 버그, 잘못된 입력 등 예측 불가능한 상황에서 발생합니다.
- 예: IllegalArgumentException, IllegalStateException, NullPointerException, IndexOutOfBoundsException, ArithmeticException
- 상속관계에서의 예외처리 - 부모 메서드가 체크 예외를 method에서 throws하지 않는 경우, 재정의된 자식 메서드도 체크 예외를 던질 수 없다. 자식 메서드는 부모 메서드가 던질 수 있는 체크 예외의 하위 타입만 던질 수 있다. 단, unchecked 예외는 무관하기때문에 checked excpetion을 catch한후 unchecked exception을 던지는 식으로 처리한다.
- Java에서 다형성을 이용하여 부모변수로 자식생성자를 받을때, 컴파일러는 부모변수의 구조만 읽을 수 있기때문에, 예외처리의 컴파일 검사를 부모기준으로 적용할 수 밖에없다. 때문에, 자식메소드는 부모의 제약에 따르도록 강제한다.
- Unchecked Exception이 선호되는 이유 : Flexibility with less code ; checked excpetion은 선택의 여지가 없이 직접 errohandling를 해야하나, unchecked excpetion은 errorhandling을 할지 안할지 결정할 수 있음. 그리고 handling시에는 별도의 코드복잡성 증가 없이 Global Exception Handler에서 일괄처리할 수 있기때문.
Exception 종류
Throwable
├── Error (Not usually caught by applications)
│ ├── LinkageError (Errors related to linking problems with classes)
│ │ ├── NoClassDefFoundError
│ │ └── ExceptionInInitializerError
│ ├── VirtualMachineError (Errors produced by the JVM making continuation impossible)
│ │ ├── OutOfMemoryError
│ │ └── StackOverflowError
│ └── AssertionError (Used for internal assertions in Java; normally not caught)
── Exception (The main exception class for catchable conditions)
├── IOException (Checked: Exceptions that must be caught or declared)
│ ├── FileNotFoundException (File not found)
│ └── EOFException (End of file reached unexpectedly)
├── RuntimeException (Unchecked: Represents programming errors)
│ ├── NullPointerException (Null object usage)
│ ├── IndexOutOfBoundsException (Accessing illegal indexes)
│ │ ├── ArrayIndexOutOfBoundsException (Invalid array index access)
│ │ └── StringIndexOutOfBoundsException (Invalid string index access)
│ ├── IllegalArgumentException (Calling methods with improper arguments)
│ │ ├── NumberFormatException (Failed number conversion)
│ │ └── IllegalThreadStateException (Operations on threads at illegal states)
│ └── ArithmeticException (Errors in arithmetic operations, e.g., division by zero)
└── SQLException (Checked: Errors related to database access)
- try-catch 예외처리 :
- try{ 예외가 발생할 수 있는 코드} catch(Exception e ){예외시 실행할 코드}
- Exception class
- .getMessage() : 오류에 대한 기본적인 내용을 출력해준다.
- .toString() : 더 자세한 예외 정보를 제공한다
- .printStackTrace() : 메소드가 내부적으로 예외 결과를 화면에 출력한다.
- try-catch 다중 예외처리 : 예외의 종류에 따라서 실행코드를 달리하고 싶을 경우 사용
- try{ 예외가 발생할 수 있는 코드} catch(예외클래스 인스턴스1; ArithmeticException ) { 예외시 실행할 코드; } catch (예외클래스 인스턴스2; ArrayIndexOutOfBoundsException){예외시 실행할 코드} cath(Exception e){예외시 실행할 코드}
- finally : try{ 예외가 발생할 수 있는 코드} catch(구체적인 예외 case ) { 예외시 실행할 코드} finally {예외와 관계없이 항상실행되는 코드}
- 사용자 정의 Exception : class를 생성하고 RuntimeException을 extends해준다. checked exception은 transaction을 rollback해주지 않음 그리고 무엇이든 throw/try-catch해주어야하는 불편함이 존재하기 때문에 unchecked exception인 runtimeexception을 extends한다
- java.util.Optional
- Optional<T> : Optional이라는 구현체를 return해서 inflow가 존재하지 않더라도 null을 반환하지않고 empty optional을 return함. List를 반환하는 쿼리에는 null이 아니라 empty list가 발생하므로, single value를 return하는 메소드에 적합함.
- isPresent(): Returns true if there is a value present, otherwise false.
- get(): Returns the value if present; throws NoSuchElementException if no value is present.
- filter(list -> !list.isempty) : empty가 아닌 list만 통과시키고 그 외에는 optional.empty()를 반환함.
- orElse(T other): Returns the value if present; returns other otherwise.
- orElseGet(Supplier<? extends T> other): Returns the value if present; returns the result produced by the supplier otherwise.
- orElseThrow(Supplier<? extends X> exceptionSupplier): Returns the contained value, if present, otherwise throws an exception to be created by the provided supplier.
- 여기서 throw가 되면 exceptionhandler가 제어흐름을 받아서 예약된 로직을 수행함.
- Optional<T> : Optional이라는 구현체를 return해서 inflow가 존재하지 않더라도 null을 반환하지않고 empty optional을 return함. List를 반환하는 쿼리에는 null이 아니라 empty list가 발생하므로, single value를 return하는 메소드에 적합함.
- 예외상황 checking
- ObjectUtils.isEmpty(company) vs company == null
- company == null - Basic Check: This is a straightforward nullity check. It simply tests whether the company object reference is null. This means it checks if the object exists at all.
- ObjectUtils.isEmpty(company) - Advanced Check: It checks if the object is either null, empty, or in some cases, based on the type of the object, if it has a default uninitialized state.
- ObjectUtils.isEmpty(company) vs company == null
문법요소
- `;` : 세미콜론으로 문장을 구분한다. 문장이 끝나면 세미콜론을 필수로 넣어주어야 한다.
- 주석 : // : 한줄주석, /* 범위 */`: 여러줄 주석
- 소괄호 `()`, 중괄호 `{}`: Class와 method의 블록을 지정, 대괄호 `[]`
연산자
- 산술연산자: `+` , `-` , `*` , `/` , `%` (단, int형 끼리의 / 연산 결과는 소수점이 제외된다)
- 증감(증가 및 감소) 연산자: `++` , `--`
- 비교연산자: `==` , `!=` , `>` , `<` , `>=` , `<=`,
- 문자열비교 :문자열이 같은지 비교할 때는 `==` 이 아니라 `.equals()` 메서드를 사용해야 한다.
- 논리비교
- `&&` (그리고) : 두 피연산자가 모두 참이면 참을 반환, 둘중 하나라도 거짓이면 거짓을 반환
- `||` (또는) : 두 피연산자 중 하나라도 참이면 참을 반환, 둘다 거짓이면 거짓을 반환
- `!` (부정) : 피연산자의 논리적 부정을 반환. 즉, 참이면 거짓을, 거짓이면 참을 반환
- 대입연산자 : `=` , `+=` , `-=` , `*=` , `/=` , `%=`
- 삼항 연산자 : `?:` ex) (조건문)? True인경우value : False인경우value
- 애매하고 가독성이 좋지 않으면 괄호()를 사용해서 연산우선순위를 확실히 해주자. (Ex :`((2 * 2) + (3 * 3)) / (3 + 2)`)
- a++` : 증감 연산자를 피연산자 뒤에 둘 수 있다. 이것을 뒤에 있다고 해서 후위(Postfix) 증감 연산자라 한다.
- ++a` : 증감 연산자를 피연산자 앞에 둘 수 있다. 이것을 앞에 있다고 해서 전위(Prefix) 증감 연산자라 한다.
- 비트연산자
- AND 연산자 (&) : 두 개의 비트 값이 모두 1인 경우에만 결과 1
- OR 연산자 (|) :두 개의 비트 값 중 하나라도 1이면 결과 1
- XOR 연산자 (^) :두 개의 비트 값이 같으면 0, 다르면 1 : NAND와 OR을 AND로 조합하여 만들어낸 비트가산기.
- 반전 연산자 (~) :비트 값이 0이면 1로, 1이면 0으로 반전
- << 연산자 :비트를 왼쪽으로 이동
- >> 연산자 :비트를 오른쪽으로 이동
- >>> 연산자 : 부호비트 상관없이 0으로 채움.
- Integer.toBinaryString(int) : 이진수 표기법으로 변환하여 String 반환
조건문 - if는 연산의 boolean 값의 분기, switch는 연산의 값의 분기에 사용된다
- if (condition1) {// 조건1이 참일 때 실행되는 코드} else if (condition2) {// 조건1이 거짓이고, 조건2가 참일 때 실행되는 코드} else {// 모든 조건이 거짓일 때 실행되는 코드}
- *if문다음에실행할명령이하나만있을경우에는 `{}` 중괄호를생략할수있다. `else if` , `else` 도마찬가지이다.
- switch (조건식) {}
case value1: /// 조건식의 결과 값이 value1일 때 실행되는 코드 break; case value2: // 조건식의 결과 값이 value2일 때 실행되는 코드 break; default; // 조건식의 결과 값이 위의 어떤 값에도 해당하지 않을때 실행하는 코드
- *if` 문은 비교 연산자를 사용할 수 있지만, `switch` 문은 단순히 값이 같은지만 비교할 수 있다. 만약 `break` 문이 없으면, 일치하는 `case` 이후의 모든 `case` 코드들이 순서대로 실행된다.
- switch의 조건은 몇가지 제한된 데이터 타입만을 사용할 수 있다. byte, short, char, int, enum, String, Character, Byte, Short, Integer. 또한, switch문은 조건에 입력된 데이터 타입이 case value에도 동일할 것이라고 가정하기때문에 value에는 타입 선언을 하지 않아도 된다.
반복문
- while문 : while (조건식) { // 코드 }
*조건식이 참이면 코드 블럭을 실행한다. 이후에 코드 블럭이 끝나면 다시 조건식 검사로 돌아가서 조건식을 검사 한다.(무한 반복)
* while문의 조건 식 내에 코드를 입력하여 간결화할 수 있다. ex ) while(input = scanner.nextInt()) != -1) ; -1 이 입력되면 while loop 종료
- do { // 코드 } while (조건식);
- *do-while` 문은 `while` 문과 비슷하지만, 조건에 상관없이 무조건 한 번은 코드를 실행한다. '
- break : break는 반복문을 즉시 종료하고 나간다.
- continue : continue는 반복문의 나머지 부분을 건너뛰고 다음 반복으로 진행하는 데 사용된다.
- for문 : for (1.초기식; 2.조건식; 4.증감식) {// 3.코드}
- 1. 초기식이 처음 한번 실행된다.
- 2. 조건식을 검증한다. 참이면 코드를 실행하고, 거짓이면 for문을 빠져나간다.
- 3. 코드를 실행한다.
- 4. 코드가 종료되면 증감식을 실행한다. 주로 초기식에 넣은 반복 횟수와 관련된 변수의 값을 증가할 때 사용한다. 다시 2. 조건식 부터 시작한다. (무한 반복)
* for문에서 초기식, 조건식, 증감식은 선택이다. 다음과 같이 모두 생략해도 된다.for문은 조건이 없으면 무한 반복한다.
- 향상된 for문 : for (int number : numbers) {code}
- 향상된 for문에는 증가하는 인덱스 값이 감추어져 있다. 따라서 `int i` 와 같은 증가하는 인덱스 값을 직접 사용해야 하
- 는 경우에는 향상된 for문을 사용하기 불편하다.
지역변수와 스코프
- 변수는 선언한 위치에 따라 지역 변수, 멤버 변수(클래스 변수, 인스턴스 변수)와 같이 분류된다.지역 변수는 본인의 코드 블록 안에서만 생존한다. 그리고 자신의 코드 블록 안에서는 얼마든지 접근할 수 있 다. 하지만 자신의 코드 블록을 벗어나면 제거되기 때문에 접근할 수 없다. **이렇게 변수의 접근 가능한 범위를 스코프(Scope)라 한다.**
- 지역변수를 사용영역에 맞도록 선언하는 것의 중요성
- 1. 비효율적인 메모리 사용**: `temp` 는 `if` 코드 블록에서만 필요하지만, `main()` 코드 블록이 종료될 때 까지 메모리 에 유지된다.
- 2. **코드 복잡성 증가**: 좋은 코드는 군더더기 없는 단순한 코드이다. 만약 `if` 코드블록안에 `temp` 를선언했다면 `if` 가끝나고나면 `temp` 를전혀생각하지 않아도된다.
- java 내에서는 variable의 유효성은 단순히 {} parenthesis 내이므로 for 이나 if statement도 별도의 local scope로 인정된다.
'개발기술 > Java' 카테고리의 다른 글
Java 코딩구현 기초 - 데이터타입 (0) | 2024.05.22 |
---|---|
Java 범용 library (0) | 2024.05.05 |
Java 코딩구현기본 - 클래스,다형성,객체지향 (0) | 2024.04.20 |
프로그래밍 언어 특징비교분석 (0) | 2024.04.09 |
Java 코딩 구현 - 개발환경설정 (0) | 2024.04.09 |