D+35-예외처리.catch문 연속사용,finally, 예외클래스.종류,처리순서, 예외떠넘기기.throws,에러메세지., javaAPI.System클래스.exit,nanoTime, Class클래스 String 클래스.CharAt,indexOf,length,replace,substring,split,trim, Math 클래스.max/min/abs,ceil/floor/round/ 날짜클래스.과거,현재

Bku·2024년 2월 15일

학원 일기

목록 보기
33/67
post-thumbnail

예외처리

예외 처리

try catch문 연속으로 사용하기

하나의 try문에 여러개의 예외가 걸릴 위험이 있다고 하면 그 에러 종류마다 catch문을 사용해주어야한다.

public class CatchByCatchApplication {
    public static void main(String[] args) {
        try {
            String data1 = args[0];
            String data2 = args[1];

            System.out.println(data1); // 에러발생
            System.out.println(data2);

            String data3 = "100";
            String data4 = "a100";

            int a = Integer.parseInt(data1);
            int b = Integer.parseInt(data2);
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println("실행 매개변수의 수가 부족합니다.");
        }catch (NumberFormatException e){
            System.out.println("숫자로 변환할 수 없습니다.");
        }catch (Exception e){
            System.out.println("에러가 발생했습니다.");
        }
    }
}


첫 번째 catch문이 실행되었다. try문에서 에러가 여러개가 발생하게 만들어 줬는데 첫 번째 문만 실행된 것을 볼 수 있다. 어차피 예외가 발생되면 바로 실행이 멈추기 때문에 try문에서 가장 처음 실행된 예외만 다루어 진다.

finally

에러가 발생하면 실행이 멈춘다고 했다. 그런데 그 뒤에도 실행을 할 내용이 있다면 finally를 이용해 나머지를 실행 할 수 있다.

public class CatchByCatchApplication {
    public static void main(String[] args) {
        try {
            String data1 = args[0];
            String data2 = args[1];

            System.out.println(data1); // out of bound 에러발생
            System.out.println(data2);

            String data3 = "100"; // number format 에러 발생
            String data4 = "a100";

            int a = Integer.parseInt(data1);
            int b = Integer.parseInt(data2);
        }catch (NumberFormatException e){
            System.out.println("숫자로 변환할 수 없습니다."); // 여기 에러만 발생
        }
        catch (ArrayIndexOutOfBoundsException e){
            System.out.println("실행 매개변수의 수가 부족합니다.");
        }catch (Exception e){
            System.out.println("에러가 발생했습니다.");
        }finally {
            System.out.println("다시 실행하세요");
        }

    }
}


이전 상황에서는 예외 처리 실행문만 출력이 되었었는데, 지금은 finally문도 실행이 된 것을 볼 수있다. 에러가 발생하여도 무조건 실행 되어야 하는 코드가 있다면 finally문을 사용하자.

예외 클래스

Exception 클래스

예외를 위한 가장 상위의 클래스이다. 이 클래스 밑에는 다양한 예외들을 처리하는 자식클래스들이 여럿 존재한다.

이 많은 예외를 모두 기억 할 수 없고 어떤 예외가 발생할 지 예상하지 못한다면 Exception을 걸어줄 수 있다.

예외 종류에 따른 처리

try안의 코드에서 여러개의 예외가 발생할 가능성이 있으면 그 예외의 종류에 따라 catch문을 만들어주어야한다. 또한 catch문의 순서도 중요하다.

예외의 순서

예외클래스들은 상속관계가 존재한다. catch문에서 예외처리를 할때 하위 클래스의 예외를 먼저 적어주어야한다. 위에서 아래로 검사대상을 읽어들이는데 하위예외도 상위클래스 타입이므로 상위예외를 먼저 적어주면 거기에 하위예외도 포함되기에 중복 처리가 일어나게 된다.

상위클래스를 먼저 작성하면 어떤 일이 일어나는 지를 확인하는 코드를 만들어보자

먼저 2개의 크기의 배열에 3개의 값을 넣고 ArrayIndexOutOfBoundsException을 유도하자
그리고 에러원일을 찾고, 실행에 문제가 있다는 내용을 출력하자.
결과

public static void main(String[] args) {
        String[] arr = {"100", "1oo"};
        for (int i = 0; i <= arr.length; i++) {
            try {
                int value = Integer.parseInt(arr[i]);
                System.out.println("arr[" + i + "]:" + value);
            }catch (ArrayIndexOutOfBoundsException e){
                System.out.println("배열 인덱스가 초과됨:" + e.getMessage());
            }catch (Exception e){
                System.out.println("실행에 문제가 있습니다.");
            }
        }
    }


두 catch문이 모두 잘 실행되었다.

이번엔 catch문의 순서를 바꿔보자

컴파일 에러가 발생한다. Exception 예외클래스가 더 상위 클래스이기 때문에 컴파일 에러가 발생하게 된다.

두개 이상의 예외 한번에 처리

두개의 예외를 같은 내용으로 처리하고 싶은 경우가 생길 수 있다. 이때는 |을 사용하여 같은 란에 한번에 적어줄 수 있다.

 public static void main(String[] args) {
        String[] arr = {"100", "1oo", null, "200"};
        for (int i = 0; i <= arr.length; i++) {
            try {
                int value = Integer.parseInt(arr[i]);
                System.out.println("arr[" + i + "]:" + value);
            }catch (ArrayIndexOutOfBoundsException e){
                System.out.println("배열 인덱스가 초과됨:" + e.getMessage());
            }catch (NullPointerException | NumberFormatException e){
                System.out.println("데이터에 문제가 있음: " + e.getMessage());
            }
        }

NumberFormatException, NumberFormatException 두 예외 모두 같은 메세지를 뜨게 할거기 때문에 한 조건문에 "|"를 이용하여 넣어주었다.
결과

결과가 잘 나온다.

예외 떠넘기기

Throws

메소드 내에서도 예외가 발생할 수 있다. 이 때 메소드 내에서 예외를 처리 할 수 있지만. 이 메소드를 실행하는 곳에서 예외를 처리 할 수도 있다. 이 때 사용해야하는 예약어가 throws이다.

사용 이유

메서드에서 예외처리를 해주었다고 해도 우리가 이 함수를 사용할 때 그것을 모르고 또 예외처리를 해 줄 수 있다.
이런 중복을 없애기 위해 throws를 사용할 수 있다. throws를 해주고 예외처리를 하지 않으면 오류가 나게 해서 예외처리를 꼭 하게 만들어준다.

코드

public class ThrowsApplication {
    public static void findClass () throws ClassNotFoundException{
        // 원래 이 메소드에서 예외를 처리해야하지만
        // 여기서 처리하지 않고 이 함수를 실행하는 곳에서 예외를 처리하게 만들 수 있다.
        // 그럴려면 Throws예약어를 사용해야한다.
        Class aClass = Class.forName("java.lang.String3"); // 클래스 이름을 리턴한다.
        System.out.println(aClass);
    }
    public static void main(String[] args) {
        try {
            findClass(); // 함수 내에서 예외처리를 해주지 않고 던졌기 때문에
            // main클래스에서 예외 처리를 해주어야한다.
        }catch (ClassNotFoundException e){
            System.out.println("클래스가 존재하지 않습니다.");
        }
    }
}


예외처리가 잘 되었다.

throws를 한 함수를 예외처리 하지않으면 컴파일 오류가 발생하게 된다.

참고 : jvm의 예외 자동 처리

참고로 main함수에서 또 throws를 사용해서 떠넘기면 jvm이 이걸 자동으로 처리해준다. 하지만 이 방법은 권장되지 않는다.

에러 메세지

에러 메세지에는 여러가지가 있지만 자주 쓰는건 getMessage이다. 이외에도 toString, printStackTrace 등이 있다.

getMessage

예외가 발생한 이유를 나타내주는 함수이다.

public class NullApplication {
    public static void main(String[] args) {
        String data = null; // 값을 나중에 지정해주려고 보통 null을 사용하는데 예외때문에 사용을 지양하는게 좋다.
        try {
            System.out.println(data.toString());
        }catch (NullPointerException e){
            System.out.println(e.getMessage());
            System.out.println("문제 발생");
        }
    }
}


결과에서 data가 null이기 때문에 예외가 발생했다는 것을 알 수있게 해준다.

Java Api

System 클래스

exit함수

프로그램을 강제로 종료하는 함수이다. 해당 실행문만 종료하는 break와는 다르게 해당 프로그램을 아예종료시킨다.
또 함수에 값을 주면 종료 코드를 반환하는데 이는 정상종료인지 비 정상종료인지를 나타낸다. 관례적으로 정상종료이면 0, 비정상종료이면 -1로 한다.

public class ExitApplication {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            if (i == 5) {
                System.exit(i);
            }
        }
        System.out.println("실행될까요?");
    }
}

아래 "실행될까요"가 출력이 안 되었고 종료코드가 5인 것으로 보아 exit가 i=5일때 실행되었다는 것을 알 수가 있다.

nanoTime함수

10의 9승분의 1시간으로 보통 실행문의 소요시간을 측정할 때 사용한다. 굉장히 큰 숫자이기에 long으로 지정해주는 것이 좋다.

public class SystemTimeApplication {
    public static void main(String[] args) {
        // 1) 처음시간 측정
        long startTime = System.nanoTime();

        // 2) 실행문 실행 : 반복문(1~1000000)
        int sum = 0;
        for (int i = 1; i < 1000000; i++) {
            sum += i;
        }

        // 3) 끝나는 시간 측정
        long endTime = System.nanoTime();

        // 4)걸린 시간 출력
        System.out.println(endTime - startTime);
    }
}


for문이 실행될때 걸린 시간을 확인 할 수있다.

Class 클래스

클래스의 메타데이터를 가지는 클래스이다.

메타데이터란

챗지피티 결과이다.

코드

public class CarApplication {
    public static void main(String[] args) {
//        Car.java : 소스 -> 컴파일(빌드) -> Car.class
        Class aClass = Car.class; // 클래스 파일 이름 Car클래스의 메타데이터를 가져온다.

//        Car 클래스 정보보기
        System.out.println(aClass.getPackage().getName()); // 패키지 정보
        System.out.println(aClass.getName()); // 패키지 + 클래스명 정보
        System.out.println(aClass.getSimpleName()); // 클래스명 정보
    }
}

Class aClass = Car.class; 를 해주면서 Car의 클래스 정보를 가져온다. 그리고 Class객체의 함수를 통해 다양한 정보를 가져올 수 있다.

String 클래스

CharAt함수

문자열에서 특정인덱스에 어떤 문자가 있는지를 확인 해주는 함수이다.

public class StringCharAtApplication {
    public static void main(String[] args) {
        String ssn = "123456-1234567";

        System.out.println(ssn.charAt(7));  // 1(남자)

    }
}


0부터 시작해서 7번째 문자는 "1"이라는 것을 확인할 수 있다.

indexOf함수

charAt과 반대로 문자열을 넣으면 인덱스를 알려주는 함수도 있다. 이것이 indexOf이다.

public class IndexOfApplication {
    public static void main(String[] args) {
        String subject = "자바 프로그램";

        // 프로그램 문자열의 위치 출력
        int pos = subject.indexOf("프로그램");
        System.out.println(pos);

        pos = subject.indexOf("1");
        System.out.println(pos);
    }
}

프로그램이 문자열에서 3index부터 시작한다는 것을 알 수있다.
또한 만약 문자열에 값이 없다면 -1을 반환한다는 것을 알 수 있다.

length함수

문자열의 길이를 알려주는 함수이다.

public class LengthApplication {
    public static void main(String[] args) {
        String ssn = "123456 - 1234567";
        int len = ssn.length();
        System.out.println(len);
    }
}


문자열의 길이를 반환한다.

replace함수

문자열에서 특정 문자열을 원하는 문자열로 바꿔주는 함수이다.

public class ReplaceApplication {
    public static void main(String[] args) {
        String old = "자바프로그램. 자바 API";

        String newStr = old.replace("자바", "Java");
        System.out.println(old);
        System.out.println(newStr);
    }
}


replace("바꿔질 문자", "바꿀 문자")를 해주면 되는데 주의점은 바꿔질 문자와 같은 문자는 모두 바뀐다는 것이다.

substring함수

문자열에서 인덱스번호를 이용해서 문자열을 잘라 반환해주는 함수이다.

public class SubStringApplication {
    public static void main(String[] args) {
        String ssn = "123456-1234567";

        // 주민번호 앞자리만 출력하기
        String newStr = ssn.substring(0, 6);
        System.out.println(ssn);
        System.out.println(newStr);
    }
}

substring함수를 이용해 주민번호 앞자리만 잘라서 가져왔다.

여기서 주의할 점은 자를 문자열의 시작 index는 가져올 문자열의 시작이지만 마지막 index는 가져올 문자열이 아닌 자르는 문자열의 시작 index여야한다.

위 코드에서 주민번호의 6번 문자열은 "-"이다. 하지만 가져온 문자열은 5인거 처럼 입력한 인덱스의 앞까지 잘라서 가져온다.

split함수

문자열을 문자기준으로 잘라서 배열에 담아주는 함수이다.

public class SplitApplication {
    public static void main(String[] args) {
        String ssn = "123456-1234567";

        // 주민번호 앞자리만 출력하기
        String[] arrStr = ssn.split("-");
        System.out.println(Arrays.toString(arrStr)); 
    }
}

"-"을 기준으로 잘려서 배열에 들어간 것을 확인 할 수 있다.

trim함수

문자열의 앞뒤 공백을 제거해주는 함수이다.
단, 문자열 가운데 있는 공백은 제거하지 않는다.

public class TrimApplication {
    public static void main(String[] args) {
        String tel = " 02";
        String tel2 = " 02 ";
        String tel3 = " 0 2 ";

        System.out.println(tel.trim());
        System.out.println(tel2.trim());
        System.out.println(tel3.trim());
    }
}


0 2의 공백은 제거되지 않았다.

Math 클래스

max/min 함수 , abs 절댓값 함수

public class MathApplication {
    public static void main(String[] args) {
        int v1 =5;
        int v2 =10;

        System.out.println(Math.max(v1, v2));
        System.out.println(Math.min(v1, v2));

        int v3 = -1;
        System.out.println(Math.abs(v3));
    }

ceil 올림함수, floor 내림함수, round 반올림함수

public class Application {
    public static void main(String[] args) {
        double v1 = 5.3;

        System.out.println(Math.ceil(v1)); // 올림 함수
        System.out.println(Math.floor(v1)); // 내림 함수
        System.out.println(Math.round(v1)); // 반올림 함수
    }
}

올림 내림 함수의 한계

이 함수들은 무조건 소수 첫 째자리에서 올림, 내림, 반올림한다. 그럼 n번 째 자리 올림 내림 반올림은 어떻게 할까

한계 극복

public class Application {
    public static void main(String[] args) {

        double v2 = 12.3456;

        System.out.println((double) Math.round(v2*100)/100); // 소수점 3번째 자리에서 반올림
        System.out.println((double) Math.ceil(v2*100)/100); // 소수점 3번째 자리에서 올림
        System.out.println((double) Math.floor(v2*100)/100); // 소수점 3번째 자리에서 내림
    }
}

10(n-1)을 곱해주고 함수처리를 한 다음 10(n-1)을 다시 나눠주면 된다.

날짜 클래스

과거의 날짜 클래스

예전에는 현재날짜 시간을 나타내기위해 Date클래스를 사용했고, 년/월/일을 표시하기위해선 Calender을 사용했다.

public class DateApplication {
    public static void main(String[] args) {
        Date date = new Date();
        System.out.println(date.toString()); // 현재 날짜

        // 추가 날짜 클래스 - date와는 다르게 년/월/일을 나타낼 수 있다.
        Calendar calendar = Calendar.getInstance();
        int y = calendar.get(Calendar.YEAR); // 현재 월
        int m = calendar.get(Calendar.MONTH) + 1; // 현재 월 (0부터 시작이라 +1해줘야한다.)
        int d= calendar.get(Calendar.DAY_OF_MONTH); // 현재 일

        System.out.println(y);
        System.out.println(m);
        System.out.println(d);
    }
}


(MONTH에는 +1을 해주어야한다.)

현재의 날짜 클래스

그런데 이렇게 두개의 클래스로 나눠서 사용하는것이 불편해서 현재는 합쳐진 다른 클래스를 사용한다.

public class LocalDateApplication {
    public static void main(String[] args) {
        // 날짜 클래스
        System.out.println("날짜 나타내기");
        LocalDate localDate = LocalDate.now();
        System.out.println(localDate);
        System.out.println(localDate.getYear());
        System.out.println(localDate.getMonth());
        System.out.println(localDate.getDayOfMonth());

        System.out.println();
        
        // 시간 클래스
        System.out.println("시간 나타내기");
        LocalTime localTime = LocalTime.now();
        System.out.println(localTime);
        System.out.println(localTime.getHour());
        System.out.println(localTime.getMinute());
        System.out.println(localTime.getSecond());
    }
}

날짜는 LocalDate, 시간은 LocalTime을 사용하면된다. 이거는 현재 시간 날짜와 년/월/일, 시/분/초를 같이 호출 할 수 있다.

profile
기억보단 기록

0개의 댓글