"아미고, 열 오두막!"

"자바를 배우게 되어 기쁩니다, 함장님!"

"안심해, 아미고. 오늘 우리는 매우 흥미로운 주제를 가지고 있습니다. Java 프로그램이 외부 리소스와 상호 작용하는 방법에 대해 이야기하고 매우 흥미로운 Java 문 하나를 연구할 것입니다. 귀를 막지 않는 것이 좋습니다."

"나는 모두 귀입니다."

"Java 프로그램이 실행될 때 때때로 Java 시스템 외부의 엔터티와 상호 작용합니다. 예를 들어 디스크의 파일과 함께 이러한 엔터티를 일반적으로 외부 리소스라고 합니다."

"그럼 내부 자원이란 무엇입니까?"

"내부 리소스는 Java 시스템 내부에서 생성된 개체입니다. 일반적으로 상호 작용은 다음 체계를 따릅니다.

Try-with-resources 문

"운영 체제는 사용 가능한 리소스를 엄격하게 추적하고 다른 프로그램에서 리소스에 대한 공유 액세스를 제어합니다. 예를 들어 한 프로그램이 파일을 변경하면 다른 프로그램이 해당 파일을 변경(또는 삭제)할 수 없습니다. 이 원칙은 그렇지 않습니다. 파일로 제한되지만 가장 쉽게 이해할 수 있는 예를 제공합니다.

"운영 체제에는 프로그램이 리소스를 획득 및/또는 해제할 수 있는 기능(API)이 있습니다. 리소스가 사용 중인 경우 리소스를 획득한 프로그램만 작업할 수 있습니다. 리소스가 사용 가능한 경우 모든 프로그램이 리소스를 획득할 수 있습니다. 그것.

"사무실에서 커피 머그를 공유한다고 상상해 보세요. 누군가 머그를 가져가면 다른 사람이 더 이상 가져갈 수 없습니다. 하지만 머그를 사용하고 씻고 제자리에 넣으면 누구나 다시 가져갈 수 있습니다."

"알았다. 지하철이나 다른 대중교통의 좌석과 같다. 자리가 비어 있으면 아무나 탈 수 있다. 자리가 꽉 차면 그 자리를 차지한 사람이 조종한다."

"그렇습니다. 이제 외부 리소스 확보 에 대해 이야기해 보겠습니다. Java 프로그램이 디스크의 파일 작업을 시작할 때마다 Java 시스템은 운영 체제에 독점 액세스를 요청합니다. 리소스가 사용 가능한 경우 Java 시스템은 그것.

"하지만 파일 작업을 마친 후에는 이 리소스(파일)를 해제해야 합니다. 즉, 더 이상 필요하지 않음을 운영 체제에 알려야 합니다. 이렇게 하지 않으면 리소스는 계속 해서 당신의 프로그램에 의해 개최됩니다."

"공평하게 들립니다."

"그렇게 유지하기 위해 운영 체제는 실행 중인 각 프로그램이 차지하는 리소스 목록을 유지 관리합니다. 프로그램이 할당된 리소스 제한을 초과하면 운영 체제는 더 이상 새 리소스를 제공하지 않습니다.

"메모리를 다 잡아먹는 프로그램 같으니라고..."

"그런 것입니다. 좋은 소식은 프로그램이 종료되면 모든 리소스가 자동으로 해제된다는 것입니다(운영 체제 자체가 이를 수행함)."

"그게 좋은 소식이라면 나쁜 소식이 있다는 뜻인가요?"

"정확히 그렇습니다. 나쁜 소식은 서버 애플리케이션을 작성하고 있다면..."

"그런데 제가 그런 애플리케이션을 작성합니까?"

"많은 서버 응용 프로그램이 Java로 작성되었으므로 업무용으로 작성할 가능성이 높습니다. 제가 말했듯이 서버 응용 프로그램을 작성하는 경우 서버는 며칠, 몇 주, 몇 달 동안 쉬지 않고 실행되어야 합니다. 등."

"즉, 프로그램이 종료되지 않으며 이는 메모리가 자동으로 해제되지 않는다는 것을 의미합니다."

"정확합니다. 그리고 하루에 100개의 파일을 열고 닫지 않으면 몇 주 안에 애플리케이션이 리소스 제한에 도달하고 충돌합니다."

"안정적인 일을 몇 달 동안 하기에는 너무 부족합니다! 어떻게 할 수 있습니까?"

"외부 리소스를 사용하는 클래스에는 리소스를 해제하는 특별한 방법이 있습니다 close().

"다음은 파일에 무언가를 쓴 다음 완료되면 파일을 닫는 프로그램의 예입니다. 즉, 운영 체제의 리소스를 해제합니다. 대략 다음과 같습니다.

암호 메모
String path = "c:\\projects\\log.txt";
FileOutputStream output = new FileOutputStream(path);
output.write(1);
output.close();
파일 경로입니다.
파일 개체 가져오기: 리소스를 가져옵니다.
파일에 쓰기
파일 닫기 - 리소스 해제

"아... 그래서 파일(또는 다른 외부 리소스) 작업을 마친 후에는 close()외부 리소스에 연결된 개체에 메서드를 호출해야 합니다."

"예. 모든 것이 간단해 보입니다. 하지만 프로그램이 실행될 때 예외가 발생할 수 있으며 외부 리소스가 해제되지 않습니다."

"그리고 그것은 매우 나쁩니다. 어떻게 해야 할까요?"

"메서드가 항상 호출되도록 하려면 코드를 - - 블록으로 래핑하고 블록 에 메서드를 추가 close()해야 합니다 . 다음과 같이 표시됩니다.trycatchfinallyclose()finally

try
{
   FileOutputStream output = new FileOutputStream(path);
   output.write(1);
   output.close();
}
catch (IOException e)
{
   e.printStackTrace();
}
finally
{
   output.close();
}

"음... 뭔가 이상해?"

"맞습니다. 이 코드는 컴파일되지 않습니다. output변수가 블록 내부에서 선언되어 블록 try{}에서 보이지 않기 때문입니다 finally.

수정하자:

FileOutputStream output = new FileOutputStream(path);

try
{
   output.write(1);
   output.close();
}
catch (IOException e)
{
   e.printStackTrace();
}
finally
{
   output.close();
}

"이제 다 괜찮아?"

"괜찮지만 FileOutputStream개체를 ​​생성할 때 오류가 발생하면 작동하지 않으며 이는 매우 쉽게 발생할 수 있습니다.

수정하자:

FileOutputStream output = null;

try
{
   output = new FileOutputStream(path);
   output.write(1);
   output.close();
}
catch (IOException e)
{
   e.printStackTrace();
}
finally
{
   output.close();
}

"그리고 이제 모든 것이 작동합니까?"

FileOutputStream"여전히 몇 가지 비판이 있습니다. 먼저 개체를 만들 때 오류가 발생하면 output변수가 null이 됩니다. 이 가능성은 블록에서 고려해야 합니다 finally.

"둘째, close()메소드는 항상 블록에서 호출되며 finally이는 try블록에서 필요하지 않음을 의미합니다. 최종 코드는 다음과 같습니다.

FileOutputStream output = null;

try
{
   output = new FileOutputStream(path);
   output.write(1);
}
catch (IOException e)
{
   e.printStackTrace();
}
finally
{
   if (output!=null)
      output.close();
}

catch" 생략할 수 있는 블록을 고려하지 않아도 3줄의 코드가 10이 됩니다. 하지만 기본적으로 파일을 열고 1을 썼을 뿐입니다."

"후우.. 결론은 잘났네. 비교적 이해는 가지만, 좀 지루하지 않나?"

"그렇습니다. 그래서 Java 제작자가 구문 설탕을 추가하여 우리를 도왔습니다. 이제 프로그램의 하이라이트 또는 이 강의로 이동하겠습니다.

try-with-resources

"7번째 버전부터 Java에는 새로운 try-with-resources 문이 있습니다.

"메소드에 대한 필수 호출 문제를 정확하게 해결하기 위해 만들어졌습니다 close()."

"유망하게 들린다!"

"일반적인 경우는 매우 간단해 보입니다.

try (ClassName name = new ClassName())
{
   Code that works with the name variable
}

"그래서 이것은 try 진술 의 또 다른 변형입니까 ?"

"예. 키워드 뒤에 괄호를 추가한 다음 try괄호 안에 외부 리소스가 있는 개체를 만들어야 합니다. 괄호 안의 각 개체에 대해 컴파일러는 섹션 finally과 메서드 호출을 추가합니다 close().

"다음은 동등한 두 가지 예입니다.

긴 코드 try-with-resources가 포함된 코드
FileOutputStream output = null;

try
{
   output = new FileOutputStream(path);
   output.write(1);
}
finally
{
   if (output!=null)
   output.close();
}
try(FileOutputStream output = new FileOutputStream(path))
{
   output.write(1);
}

"멋지네요! -with-resources를 사용하는 코드는 try훨씬 더 짧고 읽기 쉽습니다. 코드가 적을수록 오타나 기타 오류가 발생할 가능성이 줄어듭니다."

"마음에 드셨다니 다행입니다. 그런데 -with-resources 문을 추가 catch하고 finally차단할 수 있습니다 try. 또는 필요하지 않은 경우 추가할 수 없습니다.

동시에 여러 변수

"동시에 여러 파일을 열어야 하는 상황이 자주 발생할 수 있습니다. 파일을 복사한다고 가정해 봅시다. 따라서 데이터를 복사하는 파일과 데이터를 복사하는 파일의 두 개체가 필요합니다. .

"이 경우 try-with-resources 문을 사용하면 그 안에 하나가 아닌 여러 개체를 만들 수 있습니다. 개체를 만드는 코드는 세미콜론으로 구분해야 합니다. 이 문의 일반적인 모양은 다음과 같습니다.

try (ClassName name = new ClassName(); ClassName2 name2 = new ClassName2())
{
   Code that works with the name and name2 variables
}

파일 복사의 예:

짧은 코드 긴 코드
String src = "c:\\projects\\log.txt";
String dest = "c:\\projects\\copy.txt";

try(FileInputStream input = new FileInputStream(src);

FileOutputStream output = new FileOutputStream(dest))
{
   byte[] buffer = input.readAllBytes();
   output.write(buffer);
}
String src = "c:\\projects\\log.txt";
String dest = "c:\\projects\\copy.txt";

FileInputStream input = null;
FileOutputStream output = null;

try
{
   input = new FileInputStream(src);
   output = new FileOutputStream(dest);

   byte[] buffer = input.readAllBytes();
   output.write(buffer);
}
finally
{
   if (input!=null)
      input.close();
   if (output!=null)
      output.close();
}

"글쎄, 우리는 여기서 무엇을 말할 수 있습니까? try-with-resources는 멋진 것입니다!"

"우리가 말할 수 있는 것은 그것을 사용해야 한다는 것입니다."