Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Tags more
Archives
Today
Total
관리 메뉴

요리사에서 IT개발자로

스파르타 코딩클럽 부트캠프 (Java 문법 4장) 본문

Java

스파르타 코딩클럽 부트캠프 (Java 문법 4장)

H.S-Backend 2024. 5. 2. 21:06
오류(Error) 
  1. 일반적으로 회복이 불가능한 문제이다.
  2. 시스템 레벨에서 아니면 주로 환경적인 이유로 발생한다.
  3. 코드 문제로 발생하는 경우도 있으나 발생한다면 회복이 불가능하다.
예외(Exception) 
  1. 일반적으로 회복이 가능한 문제이다.
  2. 회복이 가능하다는 것은 이미 그 문제를 인지하고 대응 할 수 있다는 것.
  3. 현실적으로 코드 레벨에서 할 수 있는 문제상활에 대한 대응은 예외 처리에 속한다.

 


컴파일이란

일반적인 언어는 컴퓨터가 알아듣지 못한다.
그래서 프로그래밍 언어를 사용하여 컴퓨터가 이해할 수 있는 코드로 번역한다.

 

컴파일 에러(예외)
  1. .java 파일을 .class 파일로 컴파일할 때 발생하는 언어이다.
  2. 대부분 에러는 자바 프로그래밍 언어의 규칙을 지키지 않아서 발생한다.
  3. 컴파일 에러가 발생하는 경우 해결방법은 해당 문법에 맞게 작성하면 된다.
런타임 에러(예외)
  1. 주로 다루게 될 에러이다.
확인된 예외(Checked Exception)
  1. 컴파일 시점에 확인하는 예외다.
  2. 반드시 예외 처리를 해줘야 한다.
  3. 확인된 예외를 알면서도 처리를 하지않으면 컴파일 에러가 발생한다.
미확인된 예외(Unchecked Exception)
  1. 런타임 시점에 확인되는 예외이다.
  2. 예외 처리가 반드시 필요하지 않다.

예외 발생과 try-catch, fianlly 문

 

예외처리의 흐름

 

예외를 어떻게 정의하고

예외가 발생할 수 있음을 알리고

사용자는 예외가 발생할 수 있음을 알고 

예외를 핸들링할 것인지

 


예외 정의

//예외 클래스를 만들어서 예외를 정의한다
public class OurBadException extends Exception {

    public OurBadException() {
        super("위험한 행동을 하면 예외처리를 꼭 해야한다");
    }
}

 


 

클래스를 만들고 메서드를 만들어 우리의 메서드가 위험하다고 알리기

throw, throws

public class OurClass {

    private final boolean just = true;

    //thorows : 던지다!!(=예외를 던지다 / 발생시키다)
    public void thisMethodIsDangerous() throws OurBadException{
        //custom logic~!
        if(just){
            throw new OurBadException();
        }
    }
}

throws

메서드이름 뒤에 붙어서 어떠한 예외사항을 throws할 수 있는 지 알려주는 예약어

여러 종류의 예외 사항을 적을 수 있다.

 

throw

메서드 안에서 실제로 예외 객체를 던질 때 사용하는 예약어

실제로 던지는 예외 객체 하나와 같이 써야한다.

throw아래 구문은 실행하지않고 throw와 함계 종료한다.


package Week04.sample01;

public class StudyException {
    public static void main(String[] args) {
        OurClass ourClass = new OurClass();

        //try~catch~ finally 구문
        //try : 시도하다
        //catch : 잡다(붙잡다)
        //finally : 마침내


        //일단 try ~~ 그리고, 예외가 발생하면 그걸 잡다(catch)
        //그리고, 정상적으로 수행 또는 예외가 발생하면, 수행해야하는 로직을 finally로 수행한다.

        try{
            //1. 일단 시도한다.
            ourClass.thisMethodIsDangerous();
        } catch(OurBadException e) {
            //2.예외가 발생해서 handling 한다
            // try구문에서 예외가 발생하면 바로 코드실행을 멈추고
            //catch 구문에서 실행된다.
            System.out.println(e.getMessage());
        } finally {
            //3. 예외의 발생여부와 상관없이 실행시켜야하는 코드이다.
            //무조건 실행핟나.
            System.out.println("우리는 방금 예외를 handling 하였다. 정상 or 예외 발생하던 여기를 거친다");
        }


    }
}

 try 와 catch는 각각 중괄호 { } 를 통해 실행할 코드를 담는다.

try(시도하다)  { } 안에는 예외가 발생할 수 있으나 실행을 시도할 코드를 담는다

catch(잡는다) { } 안에는 try안에 있는 코드를 실행하다가 예외가 났을 때 실행할 코드를 담는다

 

1개의 try문에 여러개의 catch 문을 사용할 수 있다.

 

기존 try-catch의 맨 마지막 finally를 붙여 마지막에 실행할 코드를 넣는다.

 

 


  1. 문제에 직면
  2. 회복 가능한지 여부에 따라 Error와 Exception으로 나누고
  3. 예외와 에러를 컴파일 or 런타임과 같은 여러가지 기준에 나눈다.

 

문제라는 상황을 추상화, 일반화, 구체화로 정의한다.

현상황으로써 알 수 없다. => 문제

일반적으로 인식이 된다. => 오류, 예외

구체적으로 나누어 정의할 수있다 = > Checked Exception, Unchecked Exception


자바란 객체지향 프로그래밍 언어이기에

 

자바의 모든것은 현실세계 기반으로 구현이 되어있다.

현실세계에서 풀지못하는 문제가 있는것처럼

하지만 풀어낼 수 있는 문제도 있는 것처럼

 

자바란 현실세계와 비슷하게 반영되있는 프로그래밍 언어이다.

 


자바의 Throwable Class

모든 객체의 원형 Object 에서 시작한다.

위에서 정의한 문제 상황을 뜻하는 Throwble 클래스가 Object에 상속

Throwble 클래스의 자식으로

에러(Error)와 예외(Exception)클래스가 있다.

 

에러(Error) 클래스와 예외(Exception) 클래스는 각각 

IOError클래스 RuntimeException클래스와

구분되어 처리된다.

 

출처 : 스파르타 코딩클럽
출처 : 스파르타 코딩클럽


Chained Exception, 실제로 예외처리를 하는 방법

 

연결된 예외(Chained Exception)

예외는 또다른  예외를 만들 수 있다.

예외 A가 예외 B를만들면 예외 A는 B의 원인 예외이다.

 

원인 예외를 새로운 예외에 등록 => 새로운 예외 발생을

"예외 연결"

이라 한다.

 

public class main {
    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 : 진짜 예외 이유

예외 복구하기

public String getDataFromAnotherServer (String dataPath){
    try{
        return anotherServerClient.getData(dataPath).toString()
    }catch (GetDataException e){
        return defaultData;
    } //실제로 try-catch를 예외 처리하고 프로그램을 정상 상태로 복구하는 방법이다.
      
}

예외 처리 회피하기

public void someMethod() throws Exception{....}
//someMethod에 발생한 에러가 someIrresponsibleMethod의 throws를 통해 흘러나가게된다.
//보통 이런일은 하지않는다.
public void someIrresponsibleMethod() throws Exception{
    this.someMethod();
}

예외 전환하기

public void smeMethod() throws IOException{ ...}
    
    public void someResponsibleMethod () throws MoreSpecificException{
    try {
        this.smeMethod();
    }catch (IOException e){
        throw new MoreSpecificException(e.getMessage());
    }
    } //예외 처리하기 방법과 비슷하나 조금더 적절한 예외를 던져주는 경우이다.

Generic이란

타입 언어에서 중복되거나 필요 없는 코드를 줄여주는 역할을한다

그러면서도 타입 안전성을 해치지 않는다.

Public class Generic{
        public String plusReturnFuction(int a, int b) { ...}

        public String plusReturnFunction(int a, long b) {...}

        public String plusReturnFunction(int a, String b) {...}
}

보통은 위와 같이 똑같은 로직을 수행하는 함수타입을 지정해야 한다는 이유로

세차례 똑같이 반복해야한다.

 

아래와 같이 해결할 수 있다.

public class Generic{
    public Object plusReturnFunction(Object a, Object b){ ...}
}

 

자바의 모든것은 객체, 객체는 Object 클래스를 상속한다.

Object 상속을 받는다는 가정하에 위와 같이 코드를 작성한다면.

실제 타입과 상관없이 메서드 안에 두 파라미터를 전달할 수 있으나

타입 안전성이 불안하다.

그렇기에  { }안에 모든 경우의수를 준비해야한다.

 

 

Generic 문법

package Week04.sample01.gen;

// 1. 제네릭의 클래스 또는 메서드에 사용이 가능하다.
// <>안에 들어가야 할 타입을 명시하면된다.
public class Generic<T> {
    // 2. 내부 필드에 String
    private T t;
    // 3.method의 return Type도 String
    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);
    }
}

Generic 문법

public class Generic<T> {
Generic<String> stringGeneric = new Generic<>();

 

Generic<T>의 클래스처럼 제네릭을 사용한 클래스를 제네릭 클래스라한다.

제네릭에서 < >사이에 들어가는 변수명은 T (Type) 변수라 한다.

Generic 클래스를 원시타입 이라한다.

 

제네릭은 Static 멤버에 사용할 수 없다.

제네릭은 배열을 생성할 수 없다.

 

제네릭은 타입변수를 사용할 수 있다

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

}
Generic<Long, Integer, String> instance = new Generic();
instance.multiTypeMethod(longVal, intVal);

 

다형성(상속과 타입) 관계는 그대로 적용된다.

부모클래스로 제네릭 타입변수를 지정, 그안에 자식 클래스를 넘기는 것을 잘 동작한다.

 

와일드 카드를 통하여 제네릭의 제한을 구체적으로 정할 수 있다.

public class ParikingLot<T extends Car> { ...}

ParkingLot<BMW> bmwParkingLot = new ParkingLot();
parkingLot<Iphone> iphoneParkingLot = new ParkingLog();   // 에러 발생

 

<? extends T> : T와 그 자손들만 사용이 가능하다

<? super T>  : T와 그 조상들만 가능하다

<?>  : 제한이 없다

 

위처럼 제한을 하는 이유는 다형성 때문이다.

 

T는 Car의 자손클래스라고 정의하였기에

해당 클래스 내부에서 최소 Car객체에 멤버를 접근하는 코드를 적을 수 있는것이다.

 

반대로 그러한 코드들이 있을 여지가 있기에
Car 객체의 자손이 아닌 클래스를 제한하는 것이다.

 


메서드를 스코프로 제네릭을 별도 선언할 수 있다.

출처 :  Head First Java

// 또는 ...
static <T> void sort(List <T> list, Comparator<? super T> C){....}

반환 타입 앞에 <> 제네릭을 사용한 경우 해당 메서드에만 적용되는 제네릭 타입 변수를 선언할 수 있다.

타입변수를 클래스 내부의 인스터스 변수를 취급하기에

제네릭 클래스의 타입변수 static 메서드에는 사용할 수 없었다.

 

제네릭 메소드의 제네릭 타입 변수는 해당 메소드에만 적용되기 때문에

메소드 하나를 기준으로 선언하고 사용할 수 있다.

 

같은 이름의 변수를 사용했다 하더라도 제네릭 메소드의 타입 변수는 제네릭 클래스의 타입 변수와 다르다.

 

public class Generic<T, U, E> {
    //Generic <T,U,E> 의 T와 아래의 T는 이름만 같을뿐 다른 변수이다.
     static <T> void sort(List<T> list, Comparator<? super T> c) { ....}
}

 

리스트는 추상적 자료구조, 순서를 가지고,일렬로 나열한 원소들의 모임이다.

순서가 있고 중복을 허용한다는 점에서 집합(Set)과 구별된다.

 

배열은

프로그래밍 언어에서 지원하는 자료형 또는 컴퓨터공학에서 사용하는 자료구조의 하나.

순서대로 번호가 붙은 원소들이 연속적인 형태로 구성된 구조를 뜻한다.

 

 

배열

  1. 컴퓨터는 메모리의 주소를 알면 해당 메모리 칸으로 바로 접근이 가능하다.
  2. 리스트가 어디에 있든 리스트가 저장된 첫 칸의 주소만 알면 바로 접근할 수 있다.
  3. 첫 칸 옆에 순서를 가지고 저장되어 있어 "인덱스"를 이용하면 원하는 원소에 바로 접근할 수 있다.

출처 : 스파르타 코딩클럽

순서를 가지고 저장되기에 추가와 삭제가 매우느리다.

리스트의 특성을 유지하며

중간의 1을 삭제하고 싶다면

 

1을 삭제하고 1뒤에있는 3, 8,4와 같은 데이터를 한칸씩 앞으로 이동해줘야한다.

검색에는 유리하지만 수정/삭제는 불리한 자료구조이다.

 

https://namu.wiki/w/%EC%97%B0%EA%B2%B0%20%EB%A6%AC%EC%8A%A4%ED%8A%B8

 

연결 리스트

Linked List 추상적 자료형인 리스트 를 구현한 자료구조로, Linked List라는 말 그대로 어떤 데이

namu.wiki


추상적 자료구조인 리스트는 개념적으로 

 

빈리스트를 만드는 연산

리스트가 비어있는지 확인하는 연산

리스트의 앞에 원소를 삽입하는 연산

리스트의 뒤에 원소를 삽입하는 연산

리스트의 제일 첫 원소를 알아보는 연산

리스트의 첫 원소를 제외한 나머지 리스트를 알아보는 연산

 

을 지원해야한다

 


public interface List<E> extends Collection<E> {
     int size();
     boolean isEmpty();

     ....  
     boolean addAll(Collection<? extends E> c);
     boolean add(E e);

     .....
}

 

List 인터페이스는 제네릭 인터페이스 이다

타입 변수 E는 리스트에 저장되는 데이터의 타입을 타입 변수로 선언하였다.

실제로 List 속성을 가지는 구현체들에 있는 add() 메소드는

리스트 인터페이스 지정한 E라는 타입을 추가하는 데 사용된다.


출처:  https://www.javatpoint.com/collections-in-java

Collection(집합적 자료)의 속성은 lterable(순회 가능) 속성을 상속받는다.

 

Collection의 하위 속성 List, Queue, Set등이 있다.

List의 실제 구현체들은 Arr, Linked, Vector, Stack 들이 있다.

 

상황에 맞는 적절한 자료구조를 택하는 방법

인터페이스, 속성에서 코드를 보고 어떤 일을 하는지

클래스, 실제 구현체에는 위의 어떠한 일을 어떻게 해주는지

 

데이터를 다룰때 필요한 기능을 어떠한 것들이 해주는지 인터페이스에서 찾고

어떠한 방식으로 해줘야 효율적일지 실제 구현체를 보고 판단하면된다.

 


 

Wrapper 객체

출처 : 스파르타 코딩클럽

char int long과 같은 것들은

실제로 값 이상의 의의를 가지지 않는 경우가 더 많아서 원시타입 값 그대로 사용한다.

 

 

객체 특성을 이용한 추상기능 사용 또는 기본형 값, 

객체로 저장,

객체로의 기능이 필요할 때

원시형 값들을 잠시 객체로 만들어 사용할 수 있다.

 

Integer num = new Integer(17);   //Boxing
int n = num.intValue(); // UnBoxing

Character ch = 'X'; //AutoBoxing
char c = ch;  // AutoBoxing

//박싱하여 객체화 된 원시 값들은 클래스처럼 구현되어있는 메소드들을 자유롭게 이용할 수 있고
// 객체만 할 수 있는 것들을 할 수 있다.
반응형