1. 🔥 예외처리

예외(exception)

잘못된 데이터, 부정확한 데이터, 예외적인 상황에서 발생하는 오류를 말한다.

ex) 0을 나누는 연산이나, 배열의 인덱스를 넘는 것 같은 경우

Exception in thread "main" java.lang.ArithmeticException: / by zero  at ExceptionHanding.main(ExceptionHanding.java:13)  

다음과 같은 예외를 던짐

만약 이 코드가 동작 가능하게 할려면 try, catch문을 사용해야한다.

public class ExceptionHanding{
    
    static int func (int []in, int idx){
        return in[idx];
    }
    public static void main(String[] args){
        int [] arr = {1, 3, 7, 6};

        System.out.println(func(arr, 3));

        int x = 3;
        int y = 0;
        int z = 0;
        
        try{
            z = x/y;
        }
        catch(Exception e){
            System.out.println("에러 발생"+e.getMessage());
            System.exit(-1);
        }

        System.out.println(func(arr, z));
    }
    
}

문법적인 해석

try -> 조심스럽게 한번 실행 시켜봐..! catch -> 예외가 발생하면 catch로 잡아서 메세지 출력..!

즉, try에 들어가는 코드는 위험성이 있는 코드들을 짚어 넣어 예외상황이 발생할 때 catch로 잡을려고 만든 문법이다.

위 코드애서 try문에 들어가 있는 코드는 z = x/y밖에 없지만 위 main코드의 중심부분을 전부 try안에 넣어서 작성 가능하다.

규칙

  • 순차적으로 읽으면서 예외처리부분이 발생하면 catch부분으로 들어가 예외 내용 출력

1.1. 그렇다면 왜 예외처리를 사용자가 직접 사용하는가?

  1. 만약 a라는 사람이 한가지 메서드를 만들어 배포했다고 치자면 B가 그 메서드를 사용할 떄 a가 미리 그 메서드에 대한 예외를 정의 해두고 해결책을 작성해둘 수 았다.

  2. 일반적으로 코드를 작성할 때 사용자가 편하게 작성한 후 예외 처리 부분을 따로 빼서 작성 가능하기에(각각 항목에 대해 if문을 달 필요 없음) 가독성이 올라간다. ++ 구조적 예외처리

  3. 만약 예외가 발생한다면 그 자리에서 catch문으로 이동하기 때문에 그 뒤에 오류항목은 계산되지 않음

  • 또한, 위 코드에서 한가지 예외 처리만 다루었다면 catch는 다양하게 작성가능하다.

finally
finally키워드는 마지막의 실행 부분으로 catch에서 예외가 잡히든 try에서 예외가 잡히지 않든 마지막에 실행되는 부분으로 사용된다.

finally{
        System.out.println("마지막 실행부분");
    }

생략가능하다.

사용 이유

간단하게 c로 예를 들어서 설명하자면 동적할당 후에 무조건 적으로 free로 해제를 해줘여 하는 문제 처럼 예외가 발생하더라도 마지막에 실행해야하는 부분이 들어가게 된다.

자바에서는 만약 인터넷에서 읽어온 파일이 없더라도 close를 실행해줘야 하는 부분처럼 작동된다.

지금까지 다른 예외처리들은 대부분 내장되어 있는 예외처리이다.

Exception

여기서 Exception은 모든 예외처리의 조상이며 object같이 모든 예외를 받을 수 있다.

따라서 위에서 발생한 0으로 나누는 예외는 직접적인 이름이 따로 정해져 있지만 해당 예외를 Exception으로 받을 수 있다.

예외의 종류

  • error: 사용자가 해결 불가능(즉, jvm에서 발생하는 오류)
  • Runtime Exception: 프로그래밍 에러, 매우 자주알어나는 에러기 때문에 처리를 강제하지 않음(Unchecked Exception)
  • checked Exception: 반드시 처리해야하는 에러

Runtime Exception

이 경우는 위에 코드와 같이 0을 나누거나 인덱스값이 틀리거나 등등 프로그래머가 코딩중에 발생시키는 예외들이다.

즉, 프로그래밍 버그나 논리오류에 기인한다.

checked Exception

위에 에러들을 제외한 나머지 예외들을 말한다.

컴파일이 예외처리를 했는지 체크한다는 의미이고 예외처리가 강제된다.

File file = new File("test.txt");
FileInputStream out = new FileInputStream(file);
//에러 발생 -> 직접적인 예외 설정을 해줘야 함 즉 checked Exception 

try{
    File file = new File("/Users/ijeong-an/Desktop/java/test.txt");
    FileInputStream fst = new FileInputStream(file);
}
catch(IOException e) {
    e.printStackTrace();
}
//실행가능 -> 해당 파일이 없으면 예외를 던짐 

그렇다면 왜 추가적인 예외 처리를 작성해야하는가

FileInputStream라는 코드를 디자인 한 사람이 예외처리를 강제한 것.

대략적인 예외처리 구조

예외처리는 순차적으로 이루어지기 때문에 만약 가장 위에 Exception e를 catch로 잡게 된다면 이는 가장 큰 범위의 오류가 잡히게 된다.

  1. 사용자 a가 만든 새로운 예외 numberexception이 있다고 가정한다.
  2. 위의 예외를 상속받은 flatnumberexception을 만들어 예외처리를 한다고 가정할 때
  3. 대략적인 구조는 맨위에 자식의 예외, 부모, 최상위 부모(Exception)으로 처리된다.

다시한번 강조하지만 catch는 한가지 예외만 잡기 때문에 구조가 중요하다..!

1.2. 정리

  • Error예외는 따로 잡을 필요없다. -> 가상머신에서 발생하는 오류
  • Runtime Exception -> try로 꼭 묶을 필요가 없다, 빈번하게 발생하는 논리의 실수이기 때문
  • checked Exception -> 이름 그대로 예외를 체크해야한다. ex)파일 입출력

강제 예외처리

위에서 기술한 함수를 디자인한 사람이 그 함수에 대해 예외처리를 checked Exception으로 강제할 수 있다.

  • 강제하는 이유는 불안정한 함수이기 때문에 미리 경고를 하는것..!
static void func2() throws IOException{
  return ;   
}

위의 함수를 실행시키면 바로 빨간줄이 그어지고 이는 try,catch문으로 묶어야 해결된다.

이때 catch문의 예외항목은 사용자가 알고 있어야함.

throw(s) 예외를 강제로 발생시킴 따라서 사용자가 해당함수에서 발생하는 예외를 인지하게 만듬

static void func2(String name) throws IOException{
    if(name.equals("")) throw new IOException("빈문자열");
    return ;   
}

이게 기본적인 예외 처리의 작성방법이다.

  • throw(던질 예외)를 새로운 객체로 생성하여 보낸다.

즉, 코드를 실행하다 저 함수를 호출할때(throws때문에 try, catch문 작성) 빈문자열이라면 그 때 새로운 객체를 생성하여 예외를 던진다.

사용자 지정 예외

  • 사용자가 직접 Exception을 상속받아서 예외를 만들 수 있다..!
class MyFileException extends Exception{
    MyFileException(String str){
        super(str);
    }
}

위 처럼 정의하면 사용가능하다.ß

2. 🔥 Package (자바 패키지)

자바에서 패키지란 우리가 같은 이름을 가진 파일의 충돌을 방지하기 위해 디렉토리에 만드는 것 처럼 작동하는 것을 말한다.

프로젝트밑에 디렉토리 별로 관련클래스들 끼리 모아놓는다.

  • 이때 같은 클래스이름을 가진 파일이라도 디렉토리가 다르다면 충돌이 발생하지 않는다..!

패키지 특징

  1. java.util.Scanner 라는 패키지가 존재할 때 java 밑 디렉토리 util 밑 디렉토리 안에 Scanner라는 패키지가 존재한다.

  2. 대소문자 구분하지 않고 소문자로만 작성한다.

패키지 이름이 java.util인 경우라고 생각하면된다. 즉, 마지막 .을 제외허곤 이름이라고 생각

  1. 공통적으로 software.sejong.com라면 반대로 패키지 이름을 만든다. -> com.sejong.software

  2. 지금까지 사용한 패키지는 전부 디폴트 패키지이다. 디폴트 패키지는 소규모에 적합하지만 조금 큰 프로젝트를 다룬다면 비추천

  3. 높은 소프트웨어 재사용성, 패키지 계층구조, 패키지별 접근 제한

  • 만약 java.util.Scanner을 쓰기 귀찮다면 import를 통해 패키지 이름을 생략가능하다.

자바 이미지

fkdl이름이라는 프로젝트를 만들고 app.java에서 com.sejong.software/com.sejong.computer의 main을 호출시키는 모습

import com.sejong.computer.*;

public class App {
    public static void main(String[] args) throws Exception {
        System.out.println("Hello, World!");

        Test2.main(args);
    }
}

위 코드는 패키지의 모든 클래스를 import받아서 해당 패키지의 클래스의 함수를 실행시키는 모습이다.

기본 패키지(주요 패키지 / java API)

기본적으로 자바 JDK에 들어있는 패키지 java.lang ..등

  • java.lang: 자동으로 받아오기 때문에 import필요없음, 스트링, 수학, 입출력, 자바프로그래밍에 필요한 기본적인 클래스와 인터페이스 ex) math
  • java.uti: 유틸패키지, 날짜, 벡터, 해시맵 등 다양한 유틸리티 클래스와 인터페이스 제공 ex) Scanner
  • java.io: 키보드, 마우스, 프린터, 디스크등에 입출력할 수 있는 클래스와 인터페이스 제공
  • java.awt: 자바 GUI프로그래밍을 위한 클래스와 인터페이스 제공
  • java.swing: 자바 GUI프로그래밍을 위한 스윙 패키지

++추가적인 정보

현재 클래스를 묶고 있는 건 패키지라고 부르는데 이 패키지를 묶는 상위 개념이 하나 더있다.

  • module이라고 부르며

사용자가 작업중인 프로젝트에 있는 클래스를 재활용하기 위해 만들어 진 개념이며 이 말은 디폴트 패키지가 필요가 없다는 말이다…!

따라서 모듈로 가장 큰 틀을 잡고 프로젝를 생성하게 되면 각각 클래스에 맞게 패키지를 설정해줘야 한다.

큰 프로젝트에 매우 적함하다!

특징

  • 모듈을 활용하면 패키지간에 캡슐화가 가능하다(requires, exports)

2.1. java.lang패키지

java.lang에 존재하는 가장 기본적인 클래스는 object클래스이며, 모든 클래스의 수퍼클래스이다.

그렇다면 왜 java.lang패키지는 강제 상속되며 object클래스는 최상위 클래스인가..?

object클래스

  • 모든 클래스의 조상인 object을 만들어 다형성(upcasting)을 이용해서 object로 받을 수 있게 하기 위함!
  • 모든 클래스가 기본적으로 가져야하는 메서드를 정의하기 위해!

자바 이미지

아무것도 존재하지 않는 클래스를 만들어도 이미 object를 상속 받았기 때문에 기본적인 메서드들이 존재한다.

System.out.println(a);
System.out.println(a.hashCode());
System.out.println(a.getClass());
  • 위에서 만들어진 클래스를 프린터 하면 해당 클래스이름+엣지+주소가 출력된다.
  • hashcode()는 위에서 출력된 주소를 해싱(숫자로 변환)하여 출력한다. ++ 핵심은 각각의 객체마다 다른 값을 가진다..!
    ++ 객체 a, 객체 b 등호 비교를 한다면 이때 해시값을 사용한다.
  • getClass()는 해당 클래스에 대한 정보를 얻어준다. (다양한 플래그 사용가능 ex. getname())

해시값

if(a==b) //해시값이용하여 비교
  같음
else
  다름
// 만약 a = b 즉 a가 b를 참조하면 같음 연산이 이뤄짐

즉, 값을 비교하는 것이 아닌 같은 객체인지 검사함..!


그렇다면 값 비교연산은?

  • equals라는 멤버메서드를 사용해서 비교한다.
String str1 = "hello";
String str2 = "hello";
  if(str1.equals(str2))
  • 이렇게 값 비교연산은 equals를 사용한다. (기본은 해시값 비교연산)

이때, String클래스는 내부적으로 문자열 비교연산으로 만들었기 때문에 비교연산이 가능하다.

class Simple{
    int data;
    Simple(int in){
        data = in;
    }
    @Override //overring 가능한지 확인
    public boolean equals(Object o){
        if(o instanceof Simple){
            if(data == ((Simple)o).data)
                return true;
        }
        return false;
    }
}

위 코드처럼 작성하면 data가 들어있는 클래스가 object로 상속받은 equals메서드를 재정의한다. (기본은 해시값 비교이기 때문)

  • 따라서 항상 비교연산은 equals를 구현해야 한다..!
@Override
public String toString(){
    String str = this.getClass().getName()+" data :"+data;
    return str;
}

이번엔 toString()를 재정의하는 모습이다..!


Wrapper클래스

자바의 기본타입(자료형)을 클래스화 한 8개의 클래스

float 의 클래스버전은 Float이다.

int i = 10;
//Integer j = new Integer(10); //오래된 문법 오류
Integer j = Integer.valueOf(10);
i = j.intValue(); //값 전달 
  • Wrapper클래스의 객체는 다음과 같이 생성한다.
  • parse() 사용자로부터 받은 스트링값을 인자값으로 전달

태그: ,

카테고리:

업데이트:

댓글남기기