1. 개요

이 사용방법(예제)에서는 Java finally 키워드를 탐색합니다 . 오류 처리에서 try/catch 블록 과 함께 사용하는 방법을 살펴보겠습니다 . finally 는 코드 실행을 보장하기 위한 것이지만 JVM이 코드를 실행하지 않는 예외적인 상황에 대해 논의할 것입니다.

또한 finally 블록이 예기치 않은 결과를 초래할 수 있는 몇 가지 일반적인 함정에 대해서도 논의 할 것입니다.

2. 마지막으로 무엇입니까 ?

마지막으로 try 키워드 와 함께 사용하는 코드 블록을 정의합니다 . 메서드가 완료되기 전에 항상 trycatch 블록 이후에 실행되는 코드를 정의합니다 .

마지막 블록에 관계없이 예외가 발생하거나 잡은 여부 실행한다 .

2.1. 빠른 예

try-catch-finally 블록 에서 finally  를  살펴보겠습니다  .

try {
    System.out.println("The count is " + Integer.parseInt(count));
} catch (NumberFormatException e) {
    System.out.println("No count");
} finally {
    System.out.println("In finally");
}

이 예제에서 매개변수 count 의 값에 관계없이 JVM은 finally 블록을 실행하고 "In finally"를 인쇄합니다 .

2.2. catch 블록 없이 finally 사용하기

또한, 우리는 사용할 수 마지막 와 차단 시도에 상관없이 여부의 블록 캐치 블록이 존재한다 :

try {
    System.out.println("Inside try");
} finally {
    System.out.println("Inside finally");
}

그리고 우리는 출력을 얻을 것입니다:

Inside try
Inside finally

2.3. 마침내 유용한가

우리는 일반적으로 연결 닫기, 파일 닫기 또는 스레드 해제와 같은 정리 코드를 실행하기 위해 finally 블록을 사용합니다 . 예외와 상관없이 실행되기 때문입니다.

참고: try-with-resourcesfinally 블록 대신 리소스를 닫는 데 사용할 수도 있습니다 .

3. 최종적으로 실행될

JVM이 finally 블록을 실행할 때의 모든 순열을 살펴보고 더 잘 이해할 수 있습니다.

3.1. 예외가 발생하지 않음

때  시도의 블록이 완료의  마지막  도 예외가 없었다하더라도 블록이 실행됩니다

try {
    System.out.println("Inside try");
} finally {
    System.out.println("Inside finally");
}

이 예에서는 try 블록 에서 예외를 throw하지 않습니다 . 따라서 JVM은 try  블록 finally 블록 모두에서 모든 코드를 실행합니다 .

이것은 다음을 출력합니다.

Inside try
Inside finally

3.2. 예외가 발생하고 처리되지 않음

예외가 있고 catch되지 않으면 finally 블록이 계속 실행됩니다.

try {
    System.out.println("Inside try");
    throw new Exception();
} finally {
    System.out.println("Inside finally");
}

JVM은 처리되지 않은 예외의 경우에도 finally 블록을 실행합니다 .

출력은 다음과 같습니다.

Inside try
Inside finally
Exception in thread "main" java.lang.Exception

3.3. 예외가 발생하고 처리됨

예외가 있고 catch 블록에 의해 catch 되면  finally 블록이 계속 실행됩니다.

try {
    System.out.println("Inside try");
    throw new Exception();
} catch (Exception e) {
    System.out.println("Inside catch");
} finally {
    System.out.println("Inside finally");
}

이 경우 catch 블록은 throw된 예외를 처리한 다음 JVM이 finally 블록을 실행 하고 출력을 생성합니다.

Inside try
Inside catch
Inside finally

3.4. try 블록 에서 메서드 반환

메서드에서 반환하는 경우에도 finally 블록이 실행되는 것을 방지할 수 없습니다  .

try {
    System.out.println("Inside try");
    return "from try";
} finally {
    System.out.println("Inside finally");
}

여기에서 메서드에 return이 있더라도 JVM은 호출하는 메서드에 제어를 넘기기 전에 finally 블록을 실행합니다 .

우리는 출력을 얻을 것입니다:

Inside try
Inside finally

3.5. catch 블록 에서 메서드 반환

catch 블록에 return 문이 포함되어  있으면 finally 블록이 계속 호출됩니다.

try {
    System.out.println("Inside try");
    throw new Exception();
} catch (Exception e) {
    System.out.println("Inside catch");
    return "from catch";
} finally {
    System.out.println("Inside finally");
}

try 블록 에서 예외가 발생 하면 catch 블록이 예외를 처리합니다. catch 블록 에 return 문이 있지만 JVM은 호출하는 메서드에 제어를 넘기기 전에 finally 블록을 실행 하고 다음을 출력합니다.

Inside try
Inside catch
Inside finally

4. 마지막으로 실행되지 않을

우리는 항상 JVM이 finally 블록 내에서 명령문을 실행하기를 기대하지만 JVM이 finally 블록을 실행하지 않는 몇 가지 상황이 있습니다 .

운영 체제가 프로그램을 중지하면 프로그램이 모든 코드를 실행할 기회를 얻지 못할 것이라고 이미 예상할 수 있습니다. 또한 보류 중인 finally 블록 의 실행을 유사하게 방지하기 위해 취할 수 있는 몇 가지 조치가 있습니다 .

4.1. System.exit 호출

이 경우 System.exit 를 호출하여 JVM을 종료 하므로 JVM은 finally 블록을 실행하지 않습니다 .

try {
    System.out.println("Inside try");
    System.exit(1);
} finally {
    System.out.println("Inside finally");
}

이것은 다음을 출력합니다.

Inside try

4.2. 중지 호출

System.exit유사하게 Runtime.halt 에 대한 호출  도 실행을 중지하고 JVM은 finally 블록을 실행하지 않습니다 .

try {
    System.out.println("Inside try");
    Runtime.getRuntime().halt(1);
} finally {
    System.out.println("Inside finally");
}

따라서 출력은 다음과 같습니다.

Inside try

4.3. 데몬 스레드

경우 데몬 스레드가 a의 실행에 진입 시도 / 마침내 차단하고 데몬 스레드 전에 모든 다른 비 데몬 스레드 종료는 실행 마지막 블록을, JVM이 실행 완료 데몬 스레드을 기다리지 않습니다 마지막 블록을 :

Runnable runnable = () -> {
    try {
        System.out.println("Inside try");
    } finally {
        try {
            Thread.sleep(1000);
            System.out.println("Inside finally");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
};
Thread regular = new Thread(runnable);
Thread daemon = new Thread(runnable);
daemon.setDaemon(true);
regular.start();
Thread.sleep(300);
daemon.start();

이 예에서, 실행 가능한 인쇄 "내부의 시도" 빨리는 인쇄하기 전에 방법 및 1 초 대기를 입력으로 "마지막으로 내부를" .

여기에서는 약간의 지연으로 일반 스레드와 데몬 스레드를 시작합니다 . 일반 스레드가 finally 블록을 실행할 데몬 스레드는 여전히 try 블록 내에서 대기합니다 . 는 AS 일반 스레드, JVM이 또한 종료 실행 및 종료를 완료하고 기다리지 않습니다 데몬 완료 쓰레드 마지막으로 차단합니다.

출력은 다음과 같습니다.

Inside try
Inside try
Inside finally

4.4. JVM이 무한 루프에 도달함

다음  은 무한 while 루프 를 포함하는 try 블록입니다  .

try {
    System.out.println("Inside try");
    while (true) {
    }
} finally {
    System.out.println("Inside finally");
}

finally 에만 국한된 것은 아니지만  try 또는 catch 블록에 무한 루프가 포함되어 있으면 JVM이 해당 루프를 넘어서는 블록에 도달하지 않는다는 점을 언급할 가치가 있습니다.

5. 일반적인 함정

finally 블록을 사용할 때 피해야 하는 몇 가지 일반적인 함정이 있습니다.

완벽하게 합법적이지만 return 문을 사용하거나 finally 블록 에서 예외를 발생 시키는 것은 나쁜 습관으로 간주되며 어떤 대가를 치르더라도 이를 피해야 합니다.

5.1. 예외 무시

finally 블록 return은 잡히지 않는 예외를 무시합니다.

try {
    System.out.println("Inside try");
    throw new RuntimeException();
} finally {
    System.out.println("Inside finally");
    return "from finally";
}

이 경우 메서드는 throw RuntimeException을 무시하고 "from finally" 값을 반환합니다 .

5.2. 다른 return 문을 무시합니다.

반환 에 문 마지막 블록은 다른 어떤 return 문 무시 시도 또는 캐치 블록을. finally 블록 return 문만 다음을 실행합니다.

try {
    System.out.println("Inside try");
    return "from try";
} finally {
    System.out.println("Inside finally");
    return "from finally";
}

이 예에서 메서드는 항상 "from finally"를 반환 하고 try 블록 return 문을 완전히 무시합니다 . 이것은 발견하기 매우 어려운 버그일 수 있으므로 finally 블록 에서  return 사용을 피해야  합니다.

5.3. 던졌거나 반환된 내용 변경

또한 finally 블록에서 예외를 throw하는 경우 메서드 trycatch 블록 에서 throw된 예외 또는 return 문을 무시합니다 .

try {
    System.out.println("Inside try");
    return "from try";
} finally {
    throw new RuntimeException();
}

이 메서드는 값을 반환하지 않으며 항상 RuntimeException을 발생 시킵니다.

이 예제에서와 같이 의도적 으로 finally 블록 에서 예외를 throw하지 않을 수도 있지만 여전히 이 문제가 발생할 수 있습니다. finally 블록 에서 사용하는 정리 메서드가 예외를 throw 할 때 발생할 수 있습니다 .

6. 결론

이 기사에서 우리는 finally 블록이 자바에서 무엇을 하고 어떻게 사용하는지 논의 했습니다. 그런 다음 JVM이 실행하는 다양한 경우와 실행하지 않는 경우를 살펴보았습니다.

마지막으로 finally 블록 사용과 관련된 몇 가지 일반적인 함정을 살펴보았습니다 .

항상 그렇듯이 이 사용방법(예제)에 사용된 소스 코드는 GitHub에서 사용할 수 있습니다 .

Junit footer banner