質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

3回答

1035閲覧

オブジェクト破棄コードの要否

nakanak

総合スコア22

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

1クリップ

投稿2022/11/11 02:31

編集2022/11/11 10:53

質問

下記のコードを作成しました(既存のExcelファイルを開き、値を読み取るプログラム)。
プログラム自体は正常に終了するのですが、気になったのがfinally句に良く記述する「オブジェクト破棄コード」です。例示しているソースコードのコメントにも記述していますが、

Java

1 } finally { 2 // GC対象外オブジェクトは存在しないので、原則オブジェクト破棄コードは不要(下記のようなコードは不要) 3 // if(excel != null ) excel = null; 4 // if(sheet != null ) sheet = null; 5 }

上記の認識であっておりますでしょうか?

C#ですと、リソースの破棄ーC#によるプログラミング

メモリは .NET Framework の「ガーベジコレクション」機能が自動的に管理していて、 プログラマが明示的に破棄してやる必要はないのですが、 ファイルなどは「ガーベジコレクション」の管理対象外で、 明示的な破棄が必要です。

とのことですので、ファイル関係オブジェクトはその破棄コードが必要だと思いますが、Javaはそのような破棄コードは不要と考えてよろしいでしょうか?

<ソースコードサンプル>

Java

1 try{ 2 //Excelファイル オープン 3 Workbook excel = WorkbookFactory.create(new File(inputPath.toString())); 4 5 //シート オープン 6 Sheet sheet = excel.getSheet(settings.getProperty("SheetName")); 78910 11 } 12 }catch(Exception e){ 13 System.err.println("ファイル読込み失敗:" + e.toString()); 14 } finally { 15 // GC対象外オブジェクトは存在しないので、原則オブジェクト破棄コードは不要(下記のようなコードは不要) 16 // if(excel != null ) excel = null; 17 // if(sheet != null ) sheet = null; 18 }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

C# での言及

ファイルなどは「ガーベジコレクション」の管理対象外で、 明示的な破棄が必要です。

は「ファイル自体」であって「Workbook や Sheet に当たるオブジェクト」のことでは無いように思います。
java でも GC はファイル自体は削除しません。


java

1try(FileInputStream fis = new FileInputStream(args[0])) { 2 //fis から読んでなんたらかんたら 3} 4//この時点で fis は自動で close され、かつスコープを抜けるため fis は GC による回収対象となるので 5// finally で fis.close() したり fis = null する必要は無い。(例外が発生しても同様。)

java

1import java.io.File; 2 3import org.apache.poi.ss.usermodel.*; 4 5public class Main { 6 public static void main(String[] args) { 7 try(Workbook excel = WorkbookFactory.create(new File(args[0]))) { //Workbook は AutoCloseable 8 Sheet sheet = excel.getSheet("シート1"); //Sheet は close 無し 9 //(ry 10 } catch(Exception e) { 11 System.err.println("ファイル読込み失敗:" + e); 12 } 13 //excel は close され、 sheet 共々スコープを抜けて GC 対象へ 14 } 15}

投稿2022/11/11 03:11

編集2022/11/11 09:17
jimbe

総合スコア12625

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nakanak

2022/11/11 04:01

引用した部分が悪かったですね、、、 上記URL確認いただくとわかるのですが、「ファイル」ではなく「ファイルリソース(下のコードで言えば、reader)」という意味です。C# では、このreaderを明示的に破棄するコードが必要になりますが、Java では、このようなコードは不要で良いでしょうか?という、質問内容になります。 FileStream reader = new FileStream(args[0], FileMode.Open);
jimbe

2022/11/11 09:00 編集

url はマークダウンが何か間違っているようでアクセス出来ません。 「破棄」という言葉は close のことを指していて、 GC によるメモリの回収のことでは無いのではないように思います。 そのような reader であれば、今の java であれば try-resource 等で close した上でスコープを抜けることで GC に破棄させることが定石かと思いますので、 finally で null を代入することは無いと思います。
nakanak

2022/11/11 11:08

URL修正しました。すみませんでした。 「try-with-resources文」というものですね(初めて知りました)。この構文を使うことで、自動でクローズ&GC対象になるということで理解しました。自分の作っているコードも修正しようと思います。ありがとうございました。
guest

0

複数の観点が混じっているので回答もつらつらと書いた感じになりますが。


メモリは .NET Framework の「ガーベジコレクション」機能が自動的に管理していて、 プログラマが明示的に破棄してやる必要はないのですが、 ファイルなどは「ガーベジコレクション」の管理対象外で、 明示的な破棄が必要です。

は正しいとは思えません。
「"ファイルを開いている状態"を管理しているオブジェクト」はガベージコレクションの対象になります。それが他の何からも参照されていなければそのオブジェクトは破棄されます。そして破棄される時にファイルを閉じるはずです
そういった意味で"ファイルなどは「ガーベジコレクション」の管理対象外"は正しい表現には思えないです。


「WorkbookFactory.createで作られたオブジェクト」が内部に「"ファイルを開いている状態"を管理しているオブジェクト」を保持しているかどうかは分かりません。
仮に保持していたとしたらそのファイルを閉じる操作が用意されていてしかるべきです。finally節で呼ぶべきなのはその操作です。
逆に言うとそのようなファイルを閉じる操作が用意されていないなら、ファイルはすでに閉じられていて、閉じる必要がない可能性の方が高いです。

仮に保持していたとしてもそのオブジェクトは「WorkbookFactory.createで作られたオブジェクト」だけが参照していると期待されます。(複雑なキャッシュ構造などを持っているなどと考えることはないでしょう)
であれば「WorkbookFactory.createで作られたオブジェクト」がガベージコレクションの対象になった時に、「"ファイルを開いている状態"を管理しているオブジェクト」も一緒にガベージコレクションの対象になって、ファイルが閉じられるはずです。


java

1 try{ 2 //Excelファイル オープン 3 Workbook excel = WorkbookFactory.create(new File(inputPath.toString())); 4 5 //シート オープン 6 Sheet sheet = excel.getSheet(settings.getProperty("SheetName")); 78910 11 } 12 }catch(Exception e){ 13 System.err.println("ファイル読込み失敗:" + e.toString()); 14 } finally { 15 // GC対象外オブジェクトは存在しないので、原則オブジェクト破棄コードは不要(下記のようなコードは不要) 16 // if(excel != null ) excel = null; 17 // if(sheet != null ) sheet = null; 18 }

このコードの終了後に「WorkbookFactory.createで作られたオブジェクト」がガベージコレクションの対象になるかどうかは、このコードだけでは分かりません。
このコードの外側がどう書かれているかに依ります。
excel = nullsheet = nullに意味があるかどうかはこのコードだけで論じることはできません。
(ただ、最初に書いた通り、一般論としては「ファイルを閉じる操作があるならそれを呼ぶべき。ないならファイルは閉じられていてそのような操作をする必要はないだろう」なので、そもそも論じる意味がある気はしません)

投稿2022/11/11 04:20

quickquip

総合スコア11038

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nakanak

2022/11/11 11:30

「ファイルを閉じる操作」と「オブジェクト破棄の操作」を混同して質問してしまい、すみませんでした。 Workbookオブジェクトには close メソッドがあるので、try-catch-finally 構文なら、finally 句に close メソッドを記述するべきということですね。また、close メソッドを書かなかったとしても、try 句を抜けるときに、GC対象となり、GC で オブジェクト破棄されるときに自動的にclose されるということですね。 ただ、上の方が回答いただいているように、try - with -resource 文を使えば、close 文すらいらなくなるとのことですので、try - with -resource 文を使うようにします。ありがとうございました。
quickquip

2022/11/11 12:26 編集

> try 句を抜けるときに、GC対象となり、 細かい話ですが、GC対象になるのは try 文を抜けた時ではないです。これはメソッドのローカル変数扱いなのでGC対象になるのはメソッドを抜けた後です。 (普段は違いを気にすることでもないですけれど、GCの話をしている時なので書きました) (考えてみたら最初からそう書けばよかったですね)
guest

0

ベストアンサー

POIですか?
POIのWorkbookはjava.lang.AutoClosableなので、closeを呼ぶ必要があります。
try-with-resouce(C#でのusing相当)の出番でしょう。

投稿2022/11/11 04:16

matukeso

総合スコア1590

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nakanak

2022/11/11 11:15

仰る通りですね(初めて知りました)。
nakanak

2022/11/11 11:33

一番早く回答いただけたので、ベストアンサーにさせていただきました (ただ、私の質問わかりにくく、他の方も悩ませてしまい、申し訳ありませんでした)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問