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

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

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

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

Q&A

解決済

5回答

13861閲覧

for文内でのtry-catchブロック

pontaq

総合スコア31

Java

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

0グッド

0クリップ

投稿2019/02/19 01:08

編集2019/02/20 00:32

前提・実現したいこと

フォルダ内にある複数のファイルに関して、
同じ処理を行いたい。
また、例外が発生した場合は処理を抜ける

発生している問題・エラーメッセージ

抽象的で申し訳ないのですが、
for文の中にtry-catchブロックを書くことになんとなく違和感があるので、
以下のソースはjavaのお作法としてどうなのか、
ご教示いただけたらと思ってます。

該当のソースコード

java

1File[] files = new File("フォルダパス").listFiles(); 2 3 for (File file : files) 4 { 5 try (FileInputStream in = new FileInputStream(file)) 6 { 7 // 処理 } 8 catch (FileNotFoundException e) 9 { 10 e.printStackTrace(); 11 } 12 13 }

試したこと

try-with-resourcesではなく、
try-catchブロックを外出しにした方がいいのかで悩んでます。
外部からの呼び出しメソッド内です。

まだ自分の中で違和感がないのは以下です

Java

1FileInputStream fileInputStream = null; 2 try 3 { 4 for (int i = 0; i < files.length; i++) 5 { 6 fileInputStream = new FileInputStream(files[i]); 7 8 } 9 } 10 catch (FileNotFoundException e) 11 { 12 // 処理 13 } 14 finally 15 { 16 if (fileInputStream != null) 17 { 18 try 19 { 20 fileInputStream.close(); 21 } 22 catch (IOException e) 23 { 24 // 25 } 26 } 27 }

以下は通らないとわかっていますが、
これがなんとなくすっきりするというパターンです
※KSwordOfHasteさんの例5から

Java

1File[] files = new File("フォルダパス").listFiles(); 2 3 for (File file : files) 4 { 5 try (FileInputStream in = new FileInputStream(file)) 6 { 7 // 処理 } 8 }

補足情報(FW/ツールのバージョンなど)

Java8

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

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

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

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

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

azuapricot

2019/02/19 01:11

ん~。例外が起きても処理を繰り返したいのか、そこで終わりたいのか次第な気がしますけどう~ん。
stdio

2019/02/19 01:18

うむ、時と場合によるけど... ファイル関連ならありかな?とは思う。
m.ts10806

2019/02/19 01:19

Exception捕捉して何をしたいかによりますね。 文法上間違いでなければ個人的な違和感は関係なく「あり」ですし。
pontaq

2019/02/19 01:51

返信ありがとうございます。 ・例外が起きた場合、処理は中断したい ・ファイル読み込み関連 ・文法上間違いはない(デバッグで確認済み) となります。まとめてで申し訳ありません
pontaq

2019/02/19 01:57

すみません、上の文法上間違いを訂正で、 処理上の間違いはない、が正しいです。 Javaの文法に自信がありません・・・
m.ts10806

2019/02/19 01:59

コンパイル通れば文法に間違いはない ということにはなります。
Q71

2019/02/19 04:31

反対に、どのような書き方なら、違和感がないのでしょうか。 テラテイルを始め、多くの技術系QAサイトは、技術的知見の蓄積こそがメインです。あなたの「違和感がある」というのは、良い情報だと思います。そこに、「こうだと違和感がない」というのがあれば、情報の価値がさらに上がると思います。ご一考ください。
pontaq

2019/02/19 05:44

デバッグしたわけではないのですが、 try { for (int i = 0; i < files.length ; i++) { FileInputStream in = new FileInputStream(files[i]); // 処理 } } catch (FileNotFoundException e) { // 処理 } finally { if (in != null) { in.close(); } } こういう感じならまだ違和感がないです。
m.ts10806

2019/02/19 05:45

それはそれで、質問本文に追記してください。
pontaq

2019/02/19 06:07

すみません、多分実際はfinallyのif (in != null)でこけると思うので、 またあとでちゃんと考えてから追記します。
m.ts10806

2019/02/19 06:08

スコープ外ですしね。
pontaq

2019/02/20 00:22

Q71さん ありがとうございます!nakamaさんの記事内の >try-catch ブロックは、例外が発生しうる『1 行』のみを囲む。 これがもしかしたら頭の中にあって、混合していたのかもしれません(try-catch構文とtry-with-resources構文について)。 for文の中というよりは、読み込んだファイルについての処理を複数行にわたり記述することに違和感がよりあったのだと思いました。 何か違和感があるけど、これはJava初心者だからなのか、 そうではないのかがすっきりしなくて、今回質問させていただき、 その回答と自身の理解が得られてとても勉強になりました。 テラテイルの運営方針と違うかもしれませんが、大変助かりました。 今後も勉強続けていきます。
pontaq

2019/02/20 02:49 編集

ここに記載することじゃないとはわかってるのですが、言い訳させてください。 言いたいこと伝えきれずで申し訳ありませんでした。その中で全部の情報を得て答えが得られたことに本当に感謝いたします。
guest

回答5

0

ベストアンサー

想像ですがC#の書き方と比べて違う感じがするから「違和感」とおっしゃっているのではないでしょうか?

C#の構文は

・例外をハンドリングする構文=>try/catch/finally
・IDisposableなものをスコープから離れたときに自動的にDisposeする構文=>using

に分離されています。一方Javaの構文は

・例外をハンドリングする構文=>try/catch/finally
・AutoClosableなものをスコープから離れたときに自動的にCloseする構文=>try with resource

となりtryに両方の構文機能がmixされているわけです。

そのためC#で

例1:

C#

1try { 2 for (var filename : ...) { 3 using (FileStream fs = new FileStream(filename, FileMode.Read)) { 4 ... 5 } 6 } 7} catch (...) { 8 ... 9}

をそのままJavaに直すには

例2:

java

1try { 2 for (var filename : ...) { 3 try (FileInputStream fs = new FileInputStream(filename)) { 4 ... 5 } // (A) 6 } 7} catch (IOExceptio e) { // (B)ここにcatch節を書けば(A)には一々書かなくてよい 8 e.printStackTrace(); 9}

と書けばよいことになります。しかしusingと違いJavaのtry-with-resourceは例外のハンドリングを行うtry/catch/finally構文の一つのバリエーションなので
例3:

java

1 for (var filename : ...) { 2 try (FileInputStream fs = new FileInputStream(filename)) { 3 ... 4 } catch (...) { 5 e.printStackTrace(); 6 break; 7 } 8 }

とも書けます。forループのちょうど外側にtry/catchがあるケースでは内側のcatch節でbreakと書けば外側のtry/catchを書かずに済ますこともできます。ループの内側にのみtry/catchを書くか、外側にもtry/catchを書くかはやりたいことを自然に記述できるかどうかで判断すればよいと思います。上の例2/例3はエラーの発生をにぎりつぶす例ですのでcatch節にbreakを書いてますが・・・あまりよい例とは言えません。例外を握りつぶすのは普通やっちゃだめなことですよね。

自分が考える典型的パターンは「途中で何かまずいことがおきたらそのメソッド全体を失敗とする」ことなので、リソースの解放漏れさえなくせれば他に必要な例外処理はないことが多く、外側にtry/catchを書いたりメソッドにthrows句を書くより

例4:

java

1void method() { 2 for (var filename : ...) { 3 try (FileInputStream fs = new FileInputStream(filename)) { 4 ... 5 } catch (IOException e) { 6 throw new UncheckedIOException(e); 7 } 8 } 9}

こう書くことを好みます。Javaの検査例外(IOExceptionなど)はかならず外側でtry/catchで検査例外をスローしないようにハンドリングするかメソッドにthrows句を書くかどちらかを選択する必要があることに注意してください。Java以外の言語に親しんでいるプログラマーにとって「非常にうっとしいもの」に感じると思います。例4はC#でusingだけを書いた例

例5:

java

1void method() { 2 for (var filename : ...) { 3 using (FileStream fs = new FileStream(filename, FileMode.Read)) { 4 ... 5 } 6 } 7}

と同様の雰囲気のものになります。例4は検査例外IOExceptionを非検査例外UncheckedIOExceptionにすげかえているだけですが、このすげかえが必要ない(必要としない考え方の)言語(C#などJava以外のほとんど全て)で例5のように書くので、例4のような配慮が必要なJavaでは「例外のすげかえがちょっとうっとうしい」と感じる人が多いかも知れません。

投稿2019/02/19 05:44

編集2019/02/20 04:26
KSwordOfHaste

総合スコア18394

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

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

pontaq

2019/02/19 05:56

>>C#の書き方と比べて違う感じがするから「違和感」 このとおりなんだと思います。 また、今回に関しては >>途中で何かまずいことがおきたらそのメソッド全体を失敗とする でコードを書いておりました。 例4の提示ありがとうございます。参考にさせてください。 また、他の回答いただけた方々もありがとうございました。
guest

0

swordoneさんの言う通り、処理が変わってしまうため問題はないです。

処理を見る限りファイル読み込み関連なため、どこのファイルでエラーが出るのかを知りたければ、catchにログ仕込んでおくといいかもしれません。

投稿2019/02/19 02:17

stdio

総合スコア3307

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

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

0

tryを外出しした場合、1つの処理で例外が発生した時点で、forからも抜けてしまいます。
作法がどうとか以前に、処理の内容が変わってしまうわけですので問題ないです。

投稿2019/02/19 01:58

swordone

総合スコア20651

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

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

0

※書いたのに投稿しわすれていたので、遅ればせながら……せっかくなので投稿しておきます。

違和感とかなんとかではなく、このコードだと例外発生時はスタックトレース情報を出力するだけで、処理は続行されますよね?なので

  • 例外発生後も繰り返しファイル処理を可能な限り続けたい …… Forの中
  • 例外発生したら即時ループから飛びだしてファイル処理を終わらせたい …… Forの外

この基準で、どう書かという話だけです。違和感とかより先に「何を作りたいのか」を明確にして、まずはそれをそのままプログラムとして書く。違和感があっても、それで狙った動きをするのであれば「一応は完成」なので、まずは何をやりたいかを明確にして、それが実現できるかどうかを考えましょう。

違和感とかはその先の話です。

投稿2019/02/19 04:15

backyard

総合スコア534

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

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

pontaq

2019/02/19 05:31

コード不足申し訳ないです。 実際はcatchの中にreturn null;が入ります。 思った動きはしてくれているのですが、上にも書いてあるとおり、 ただ漠然と違和感がある、と思って質問してみました。 こちらの運用方針からそれる質問でしたら申し訳ありません。
backyard

2019/02/19 05:52

そういうことでしたら、やはり「あなたがそうする理由を述べられるのであれば、違和感を感じる必要は無い」ですね。二つの同等の選択肢があり、どっちを選ぶか、という話であれば好みや違和感で選択を決めますが、ループ内の例外処理を出すか、入れるかはたいていの場合「そうしなければならない理由」とともに決められる物だと思うので、違和感を感じようが感じまいが「書くべきように書く」ということになるかと。 プログラムにしても設計にしてもすべては「そうした理由」があるべきで、作り手はそれをきちんと説明できないと行けません。違和感があるならば、その違和感の原因をきちんと考えるべきかと。少なくとも私は違和感を感じません。 お望みの答えではないかもしれませんが何かの参考になれば。
guest

0

「for文の中にtry-catchブロックを書くこと」がお作法的に NG ということはないと思います。

質問者さんの「なんとなく違和感」の理由がわからないと何とも言えません。

投稿2019/02/19 01:33

nskydiving

総合スコア6500

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

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

pontaq

2019/02/19 01:55

回答ありがとうございます。 C#のusingのつもりでtry-with-resourcesを使用していたのですが (そもそもこの感覚が間違いならすみません)、 ループ文の中にtry構文を書くことへの違和感としかいえないです。 個人的主観とJava初心者なので、 Javaの有識者からのご意見が欲しく、質問しました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問