오늘의 학습 키워드
- 오류 및 예외처리
- 제네릭
- 정규식
오류 및 예외처리
코드 실행 관점에서의 예외 종류
- 컴파일 에러
- 런타임 에러
예외 처리 관점에서의 예외 종류
- 확인된 예외 (Checked Exception)
- 미확인된 예외 (Unchecked Exception)
예외 정의하기
class OurBadException extends Exception {
public OurBadException() {
super("위험한 행동을 하면 예외처리를 꼭 해야합니다!");
}
}
예외 처리 사용하기
class OurClass {
private final Boolean just = true;
// 신규 문법 throws!
public void thisMethodIsDangerous() throws OurBadException {
if (just) {
// 신규 문법 throw!
throw new OurBadException();
}
}
}
throws
: 메소드 이름 뒤에 붙어 이 메소드가 어떠한 예외사항을 던질 수 있는지 알려주는 예약어, 여러종류 나열 가능
: 이 예약어가 붙은 메소드는 예외가 발생할수 있으므로, 다른곳에서 사용시 try catch 문 안에서 사용되거나, try catch문 없이 사용되려면, 사용하려는 메소드 역시 throws를 선언해야 한다
throw
: 메소드 안에서, 실제로 예외 객체를 던질 때 사용하는 예약어, 예외 객체 하나와 같이 사용되어야 한다
동작은 return 키워드처럼 throw 아래의 구문들은 실행되지 않고 throw 문과 함께 메소드 종료
예외의 Handling : try - catch - (finally)
public class StudyException {
public static void main(String[] args) {
OurClass ourClass = new OurClass();
try {
// 1. 위험한 메소드의 실행을 "시도" 해 봅니다.
// "시도" 해보는 코드가 들어가는 블럭입니다.
ourClass.thisMethodIsDangerous();
} catch (OurBadException e) {
// 2. 예외가 발생하면, "잡아서" handling 합니다.
// 예외가 발생하는경우 "handling" 하는 코드가 들어가는 블럭입니다.
// 즉 try 블럭 내의 구문을 실행하다가 예외가 발생하면
// 예외가 발생한 줄에서 바로 코드 실행을 멈추고
// 여기 있는 catch 블럭 내의 코드가 실행됩니다.
System.out.println(e.getMessage());
} finally {
// 3. 예외의 발생 여부와 상관없이, 실행시켜야 하는 코드가 들어갑니다.
// 무조건 실행되는 코드가 들어가는 블럭입니다.
System.out.println("우리는 방금 예외를 handling 했습니다!");
}
}
}
// thisMethodIsDangerous() 메소드는 예외가 발생할수 있어서 throws된 메소드
// throw된 예외객체타입을 catch문으로 넣어준다 (thisMethod 안에서 throw함)
// finally 구문은 선택
예외처리 핸들링 흐름 총 정리
- try - catch는 각각 중괄호{}를 통해 실행할 코드들을 담습니다.
- try 단어의 “시도한다”라는 뜻에 맞게 중괄호{} 안에는 예외가 발생할 수 있지만 실행을 시도할 코드를 담습니다.
- catch 단어의 “잡는다”라는 의미에 맞게 중괄호{} 안에는 try 안에 있는 코드를 실행하다가 예외가 났을 때 실행할 코드를 담습니다.
- catch 는 소괄호()를 통해 어떤 예외 클래스를 받아서 처리할지 정의해 주어야 합니다.
- catch로 모든 예외를 다 받고 싶으면 Exception 을 넣어주면 됩니다. << 사용자 지정 및 기타 구현체 예외객체는 모두 Exception을 부모로 두기때문에 어떤 예외든 부모타입으로 받아낼 수 있다
- catch로 일부 예외만 받아서 처리하고 싶으면 해당 예외 클래스명을 넣어주면 됩니다.
- 1개의 try 문에 catch 문은 여러 개 사용할 수 있습니다. ex) 1try : 4catch
- 기존 try - catch*의 맨 마지막에 finally를 붙여서 마지막에 반드시 실행할 코드를 넣을 수 있습니다.
예외 연결
왜 예외를 연결하죠?
예외를 연결하는 이유는 여러 가지 예외를 하나의 큰 분류의 예외로 묶어서 다루기 위함입니다. checked exception을 unchecked exception으로 포장(wrapping) 하는데 유용하게 사용되기도 합니다.
> Q point : 왜 checked를 unchecked로 포장해야 하는지?
initCause()
- 지정한 예외를 원인 예외로 등록하는 메소드
getCause()
- 원인 예외를 반환하는 메소드
try {
// 예외 생성
NumberFormatException ex = new NumberFormatException("가짜 예외이유");
// 원인 예외 설정(지정한 예외를 원인 예외로 등록)
ex.initCause(new NullPointerException("진짜 예외이유"));
// 예외를 직접 던집니다.
throw ex;
} catch (NumberFormatException ex) {
// 예외 로그 출력
ex.printStackTrace();
// 예외 원인 조회 후 출력
ex.getCause().printStackTrace();
}
// checked exception 을 감싸서 unchecked exception 안에 넣습니다.
throw new RuntimeException(new Exception("이것이 진짜 예외 이유 입니다."));
}
실제 예외 처리하는 3가지 방법
- 예외 복구하기
- 예외 처리 회피하기
- 예외 전환하기
// 예외 복구
public String getDataFromAnotherServer(String dataPath) {
try {
return anotherServerClient.getData(dataPath).toString();
} catch (GetDataException e) {
return defaultData;
}
}
// 예외 처리 회피
public void someMethod() throws Exception { ... }
public void someIrresponsibleMethod() throws Exception {
this.someMethod();
}
// 이 경우 someIrresponsibleMethod()를 사용하려는 다른 곳에서 처리를 해줘야 하기때문에 회피
// 예외 전환
public void someMethod() throws IOException { ... }
public void someResponsibleMethod() throws MoreSpecificException {
try {
this.someMethod();
} catch (IOException e) {
throw new MoreSpecificException(e.getMessage());
}
}
결론?
throws 는 예외처리 떠넘기기 - 이것을 선언한 메소드는 자신을 사용하려는 모든곳에서 예외처리를 하게만듬
throw는 예외 발생지점, try 문 안에서 throw는 catch로 예외객체 전달, 그 외의 곳에서 throw는 예외발생! 실행종료
느낌(종료하며 메시지 출력 가능)
제네릭
제네릭의 사용이유
- 타입 언어에서 중복되거나 필요 없는 코드를 줄이기 위해
- 유연함을 가져가면서 타입 안정성을 해치지 않기 위해
제네릭 정의 및 사용
public class Generic<T> {
// 2.
private T t;
// 3.
public T get() {
return this.t;
}
public void set(T t) {
this.t = t;
}
public static void main(String[] args) {
// 4.
Generic<String> stringGeneric = new Generic<>();
// 5.
stringGeneric.set("Hello World");
String tValueTurnOutWithString = stringGeneric.get();
System.out.println(tValueTurnOutWithString);
}
}
제네릭의 제한사항
- 객체의 static 멤버에 사용할 수 없다 ( 타입변수 T 를 클래스 내부의 인스턴스 변수 취급하기때문 )
- 제네릭 배열을 생성할 수 없다
static T get() { ... } // 에러
static void set(T t) { ... } // 에러
제네릭의 문법
- 다수의 타입변수 사용가능
- 다형성 -> 상속과 타입의 관계는 그대로 적용
- 와일드카드를 통해 제네릭의 제한을 구체적으로 정할 수 있다
- 메소드를 클래스와 별개의 영역으로 제네릭을 별도로 선언 할 수 있다 << 중요!
와일드 카드 :
<? extends T> : T와 그 자손들만 사용 가능
<? super T> : T와 그 조상들만 가능
<?> : 제한 없음
static <T> void sort(List<T> list, Comparator<? super T> c) { ... }
위 코드를 보면 메소드의 반환타입(void) 앞에 제네릭 타입변수 <T> 가 있다, 이런 경우 해당 메소드에만 적용되는
타입변수T가 존재하게 된다 (클래스에서 제네릭을 사용해 T를 선언했더라도 이와는 별개)
이 타입변수는 클래스가 아닌 메소드를 스코프로 동작하기 때문에 static이 선언되어있어도 잘 사용할 수 있다.
public class Generic<T, U, E> {
// Generic<T,U,E> 의 T와 아래의 T는 이름만 같을뿐 다른 변수
static <T> void sort(List<T> list, Comparator<? super T> c) { ... }
}
정규식
정규표현식이란 문자열 데이터 중에서 원하는 조건(패턴)과 일치하는 문자열 부분을 찾아내기 위해
사용하는 것으로, 미리 정의된 기호와 문자를 이용해서 작성한 '문자열'
정규식을 이용하면 많은 양의 텍스트 파일(혹은 문자열 데이터) 중에서 원하는 데이터를 손쉽게 뽑아낼 수 있고
입력된 데이터가 형식에 맞는지 체크하기도 쉽다
다만 단점으로는 가독성이 떨어진다는 부분
정규표현식 기본 기호
. | 임의의 문자 1개를 의미 | "^." = 임의의 문자 1개 |
^ | 시작을 의미!, [ ]괄호안에 있다면 부정의 의미 | ^a = a로 시작하는 것 |
$ | $앞의 문자열로 문자가 끝나는지 의미 | a$ = a로 끝나는 것 |
[ ] | [ ] 괄호 안의 문자가 있는지를 의미 | [ab][cd] = ab중 한 문자, cd중 한 문자 의미 |
[ ^ ] | [ ] 괄호 안에 ^ 문자가 있다면 부정,제외를 의미 | [^0-9] = 0~9를 제외한 나머지 |
- | 사이의 문자 혹은 숫자를 의미 | [a-z] = 소문자 a부터 z까지 |
| | 또는 | ab|bc |
( ) | 그룹 | 01(0|1) 01 뒤에 0or1이 들어간다 |
{ } | 개수 | |
\b | 공백, 탭, "," "/" 이 4가지 의미 | |
\B | \b의 부정 | |
\d | 0~9사이의 숫자 | |
\D | \d의 부정 | |
\s | 공백, 탭 의미 | |
\S | 공백, 탭이 아닌 문자 | |
\w | 알파벳 대소문자, 숫자, "_" 의미 | |
\W | \w의 부 |
정규식에서 [ ] 는 문자클래스, [ ] 안에 들어가있으면 아래의 메타문자들 역시 그냥 단순 문자로 본다!
다만 ^ 만 예외적으로 반대를 의미
. ^ $ * + ? {} [] \ | ()
// 정규식의 예제를 통해 감 잡기
1. a.b : 이 정규식의 의미는 " a + 모든문자 + b" 와 같다
>> aab, a0b, abc 중 해당되지 않는 문자열은?
2. a[.]b : 이 정규식의 의미는 a.b 이다, [ ] 안에는 메타문자 .도 그냥 단순 문자이기때문
3. [ab][cd] 와 ab|cd 의 차이점 (1)은 ac,ad,bcdf 등 최소 ab중 하나 cd중 하나꼭 잇어야함
(2)는 ab,cdf,이런식으로 최소 ab나 cd는 꼭 붙어야함
4. a.b.*d$ : 이 정규식의 의미는 "a + 모든문자 + b + 0개이상 모든문자 + d" 로 끝나는 문자열 의미
>> aqbd, a9bPO7d 해당, abPO7d, a4bd0 틀림
이외에 /d = [0-9] 와 동일 /w = [a-zA-Z0-9_] 와 동일
정규표현식 수량 기호
? | ? 앞의 표현식이 없거나 최대 한개만 | a1? : 1이 최대 한개만 있거나 없을수있다 |
* | 앞의 표현식이 0개 이상 | a7* : 7이 0개이상 있다 |
+ | 앞의 표현식이 1개 이상 | aQ+ : Q가 1개이상 있다 |
{n} | 딱 n개 있다 | a{3} a가 3개있다 = aaa |
{n, m} | n개 이상 m개 이하 | a{3,5} a가 3개이상 5개이하 있다 |
{n,} | n개 이 | a{5,} a가 5개 이상있 |
정규표현식 캡쳐 기호 ( 여기서 캡쳐란 원하는 부분만을 추출하고 싶을 때 사용하는 것 (메소드와 연계) )
( ) | 그룹 및 캡쳐 | |
( ?: ) | 찾지만 그룹에 포함 안됨 | |
( ?= ) | =앞 문자를 기준으로 전방 탐색 | |
( ?<= ) | =뒤 문자를 기준으로 후방 탐색 |
'TIL > Web Back' 카테고리의 다른 글
[Sparta] 내일배움캠프 6일차 TIL (0) | 2024.04.26 |
---|---|
[Sparta] 내일배움캠프 5일차 TIL (0) | 2024.04.25 |
[Sparta] 내일배움캠프 3일차 TIL (0) | 2024.04.23 |
[Sparta] TIL 2일차 (0) | 2024.04.22 |
[Sparta] TIL 1일차 (1) | 2024.04.19 |