231018 Java 문법 종합반 chapter4

MJ·2023년 10월 18일

Java 문법 종합반

목록 보기
4/5

[학습목표]
1. 오류 및 예외의 개념에 대해서 이해합니다.
2. 예외 클래스 구조를 이해하고 동작하는 방식을 이해합니다.
3. 예외 발생시 try-catch, finally 문으로 다루는 방법을 배웁니다.
4. 예외를 직접 발생시키는 방법을 배워봅니다.
5. 예외 클래스의 구조가 자바에서 어떻게 구현되어있는지 알아봅니다.
6. 실질적으로 어떻게 예외를 고려하여 프로그래밍을 하는지 알아봅니다.
7. Generic 문법이 왜 필요한지, 어떠한 효용이 있는지 배웁니다.
8. Generic의 세부적인 문법을 배웁니다.
9. 가장 대표적인 Generic의 사용 예시 중 하나인 Collection이 어떻게 구현되어있는지 알아봅니다.
10. Wrapper 객체에 대하여 알아봅니다.

1.예외처리

1)오류 및 예외에 대한 이해

사용자가 숫자가 아닌 문자 입력, 감당할 수 없는 숫자 입력,메모리 부족
=>정의해놔서 대응

오류/예외처리 습관화+>완벽에 가까운 프로그램
<문제 직면 -> 회복 가능한지 여부>

  • 오류(Error): 회복이 불가능 ->프로그램 종료
    시스템 레벨/ 환경적이유
  • 예외(Exception):회복이 가능 -> handling가능
    <예외 종류>
    • 컴파일 에러: 문법(규칙) 틀림->문법에 맞게 작성(인텔리제이가 체크)
    • 런타임 에러: 실행하고 나서 발생
      문법적인 오류X, 컴파일은 잘됬음

<예외 처리 관점에서 예외 종류>

  • 확인된 에러(Checked Exception): (!= 컴파일 에러)
    문제 인지 하고 있었어서 정의해두었고 이를 확인할 수 있음
    => checkedException에 대한 예외처리 안하면 컴파일 에러 발생
  • 미확인 에러(Unchecked Exception):
    런타임 시점에 확인(예측X), 예외처리가 반드시 필요하지는 않음

2)예외 발생과 try-catch문, finally문

<주의점>
1. 예외를 어떻게 정의
2. 예외가 발생할 수 있음을 알리고(로직에 flag달아놓음)
3. 어떻게 알고 예외 핸들링하는지

throws vs throw

  • throws : 메서드 이름 뒤에 붙어 어떤 예외사항을 던질 수 있는지 알려주는 예약어, 여러개 가능

그냥 Exception써도 되지만 상속받아서 구체적인 Exception 적시하는게 좋음

  • throw :
    • 메서드 안에서 실제 예외 객체 던질 때 사용
    • 실제 예외객체와 같이 써야함.
    • 일반 메서드 return 처럼 메서드 종료

<용어 정리>
checked Excepition
예외 발생하는 상황 인지, 어떤 에러인지 정의
메서드를 선언 할 때 예외가 발생하는 위험한 메서드라는 것을 알렸다!
(throws,throw)
메서드 사용시 예외처리 하지 않으면 컴파일에러!(빨간줄)

예외처리
try : 시도하다
catch : 집다 붙잡다
finally : 마침내

-일단 try해 그리고, 예외 발생하면 잡아(catch)
-그리고, 정상적으로 수행되든, 예외가 발생하든, 마침내 수행되야하는 로직 'finally' 수행해!!

try {
	 //일단 실행
 	ourClass.thisMethodIsDanger();//빨간 줄 -> 위험하기 때문에
} catch (OurBadException e) {
       //무슨종류 예외 캐치할 것인지 명시 -> 인스턴스 화		           System.out.println(e.getMessage());
} finally {
	//무조건 여기는 거친다.
    System.out.println("우리는 방금 예외를 Handling했습니다. 정상처리되든, 예외사항이 발생하든 여기를 거쳐요!");
 }

3)예외 클래스 구조 이해

문제상황을 추상화 일반화 구체화 해서 정의
1. 추상적인 문제
2. 구체적인 오류,예외
3. 더 구체적인 checked exception, Unchecked Exception로 정의

  • Java 차원에서 에러 객체 제공
    어떻게 구현되어있는지 공부!! =>커스텀

Throwable Class

Object클래스 상속
자식으로 Error 클래스 Exception 클래스 -> 그아래 IOError, RuntimeException

* RuntimeException을 상속한 예외들은 UncheckedException,
반대로 상속하지 않은 예외들은 CheckedException으로 구현

컴파일 시점에 알 수 없고, 사용자의 입력에 따라 달라짐->RunTimeException =>UncheckedException

4)Chained Exception, 실제 예외 처리하는 방법

연결된 예외(Chained Exception)

  • 예외는 다른 예외 유발
    A가 B를 발생시켰다면 A가 B의 원인(init)
  • 원인 예외를 새로운 예외에 등록 후 새로운 예외 발생 => 예외 연결

why 연결??
예외 사항 여러개를 한개로 묶어서 처리
CheckedException(컴파일시 핸들링처리해야 에러X=>길어짐)을 UncheckedException으로 포장(Wrapping)함

<원인 예외 다루기 위한 메소드>

  • initCause():예외 연결
    B.initCause(A); => A가 B의 원인

  • getCause():연결한 예외 반환(어떤 내용인지 조회)

// 연결된 예외 
public class main {

    public static void main(String[] args) {
        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("이것이 진짜 예외 이유 입니다."));
    }
}

// 출력
Caused by: java.lang.NullPointerException: 진짜 예외이유

실제 예외 처리 방법

(1)예외 복구

public String getDataFromAnotherServer(String dataPath) {
		try {
				return anotherServerClient.getData(dataPath).toString();
		} catch (GetDataException e) {
				return defaultData;
		}
}

기본적인 방식이지만, 현실적으로 복구가 가능한 상황이 아닌 경우가 많거나 최소한의 대응만 가능한 경우가 많기 때문에 자주 사용되지는 않습니다.

(2)예외처리회피

public void someMethod() throws Exception { ... }

public void someIrresponsibleMethod() throws Exception {
		this.someMethod();
}

<같은 객체 내X>

someMethod()에서 발생한 에러가 someIrresponsibleMethod()의 throws를 통해서 그대로 다시 흘러나가게됨.

(3)예외전환

public void someMethod() throws IOException { ... }

public void someResponsibleMethod() throws MoreSpecificException {
		try {
			this.someMethod();
		} catch (IOException e) {
			throw new MoreSpecificException(e.getMessage());
		}
}
  • 예외처리 회피하기의 방법과 비슷하지만, 조금더 적절한 예외를 던져주는 경우 입니다.
  • 보통은 예외처리에 더 신경쓰고싶은 경우나, 오히려 RuntimeException처럼 일괄적으로 처리하기 편한 예외로 바꿔서 던지고 싶은 경우 사용합니다.

2.제네릭

1)Generic

타입을 유연하게 다루기!
generalized(일반화된)+genetid(유전적인)

효용(타입언어에서 중복되거나 필요없는 코드 줄여줌, 타입안정성 침해하지지 않음)

[기존의 문제]
1)약타입 언어(파이썬, 자바스크립트)->매개변수 타입 지정없이 함수 구현
but, Java는 over-loading해야함(매서드 명 같지만, 매개변수 타입 다르면 다시 구현)
2) 매개변수를 모두 Object로 구현하면

문제 발생)객체 단항 연산자 사용 X(++,--,!,(type), +,-(부호),~(비트반전)), 타입, 순서 구분 안됨 => {}안에 모든 경우의 수 대비해야함!

=>타입 안정성 침해하기 때문에 안됨

=>> Generic으로 구현해 해결

javascript->typescript로 바뀌고 있음

2)Generic 문법

// 1.제네릭은 클래스 또는 메서드에 사용
//클래스 이름 뒤에 <> 문법 안에 들어가야 할 타입 변수를 지정합니다. 
//타입변수의 이름을 T로 사용하는 이유는 일종의 컨벤션
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.매개변수에 String
        stringGeneric.set("Hello World");
				
        String tValueTurnOutWithString = stringGeneric.get();

        System.out.println(tValueTurnOutWithString);
    }
}

<용어 정리>

  • 제네릭 클래스: 제니릭을 사용한 클래스, 원시 타입이라고 한다.
  • 타입 변수:<> 안에 들어가는 변수명 T

<제네릭의 제한>

  • static 멤버: 사용 불가->모든 객체에 동일하게 동작
    타입변수는 인스턴스 변수로 간주됨
  • 제네릭 배열 생성 불가!

<문법>
1. 다수의 타입변수 사용가능

public class Generic<T, U, E> {
    public E multiTypeMethod(T t, U u) { ... }
}


Generic<Long, Integer, String> instance = new Generic();
instance.multiTypeMethod(longVal, intVal);
  1. 다형성(상속)과 타입 관계 그대로 적용
  2. 와일드 카드를 통해 제네릭의 제한 구체적으로 정할 수 있음
  • <? extends T> : T와 그 자손들만 사용 가능
  • <? super T> : T와 그 조상들만 가능
  • <?> : 제한 없음
public class ParkingLot<T extends Car> { ... }

ParkingLot<BMW> bmwParkingLot = new ParkingLot();
ParkingLot<Iphone> iphoneParkingLot = new ParkingLog(); // error!

*제한하는 이유 다형성 때문!
4.메서드에 스코프로 제네릭 선언가능

//반환 타입 앞에 <> 사용 -> 해당 메서드에만 적용되는 제네릭 타입변수 선언
//제네릭 클래스내의 static 메소드에서 사용 불가(타입 변수가 인스턴스 변수라서)
//but. 메소드 하나를 기준으로 선언하고 사용은 가능-> 제네릭 메소드

public static <T extends Comparable<? super T>> void sort(List<T> list)

static <T> void sort(List<T> list,Comparator<? super T> c) {...}
  1. 같은 변수 이름 사용했어도
    제네릭 메소드 타입변수 != 제네릭 클래스 타입변수
public class Generic<T, U, E> {
		// Generic<T,U,E> 의 T와 아래의 T는 이름만 같을뿐 다른 변수
    static <T> void sort(List<T> list, Comparator<? super T> c) { ... }
}

3)Collection

  • List 다시보기

추상적 자료구조
List(인터페이스)->ArrayList(class), LinkedList(class)로 구현
순서를 가지고 일렬로 나열, 중복허용 <->Set(순서X,중복허용X)

  • 배열(Array)과 리스트 특징
    조회관점 :주소만 알면 빠르게 알수 있음(연속적으로 있어서), index로 접근
    수정/삭제 관점 : 땡기고 밀고해야해서 느리다.
    *검색에는 유리하고 수정 삭제는 불리한 자료구조 -> Stack,Queue로 보완

  • 추상적(인터페이스,추상클래스): 메소드만 정의하고 구현체에서 가져다가 실제로 구현

  • List 인터페이스 : 여러 연산 정의->구현부X
    size(), imEmpty(), contains(Object), add(E e),remove(Object o) 등등!!!

4)Wrapper 객체

  • 원시타입(char, byte, short, int, long,float,double,boolean)
    :값 자체만 의미 잇음, 가벼움
  • Wrapper class(Character, Byte, Short, Integer, Long,Float,Double,Boolean)
    :원싯타입을 추상화(인스턴스화), 무거워서 기능필요할 때만 씀 boxing,unboxing,autoboxing
    Integer num = new Integer(17);  // Boxing
    int n = num.intValue(); // UnBoxing

Character ch = 'X'; // AutoBoxing(jdk 1.5 이상 부터)
char c = ch; // AutoUnBoxing

0개의 댓글