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

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

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

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

Q&A

解決済

3回答

3506閲覧

try-catch-finallyの挙動について

退会済みユーザー

退会済みユーザー

総合スコア0

Java

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

0グッド

0クリップ

投稿2019/07/23 09:59

前提・実現したいこと

oracle java se8 silverの資格の為の勉強をしています。

try-catch-finallyにてcatchブロック内でreturnする前にfinallyブロックで変数に+10しているのですが反映されない理由がわかりません。

もともとの問題はsampleメソッドの中のval変数はint型でプリミティブ型です。この解答には納得がいきます。

解答には続きがあり、変数を参照型に変更すればfinallyブロックの処理が適用されるはずだとあります。結果として反映されないのですが理由がわかりません。

どなたかわかる方回答よろしくお願いいたします。

該当のソースコード

Java

1public class Main { 2 public static void main(String[] args) { 3 Integer result = sample(); 4         //-> 10 (プリミティブ型) 5 //-> 20 (参照型になるはず) 6 } 7 8 9 private static Integer sample() { 10 Integer val = new Integer(0); 11 try { 12 String[] array = {"A", "B", "C"}; 13 System.out.println(array[3]); 14 } catch(RuntimeException e) { 15 val = 10; 16 return val; 17 } finally { 18 val += 10; 19 } 20 return val; 21 } 22}

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

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

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

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

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

guest

回答3

0

ベストアンサー

解答には続きがあり、変数を参照型に変更すればfinallyブロックの処理が適用されるはずだとあります。

次のように、参照先が変わらない例を用いると良いです。

Java

1import java.util.*; 2 3 4class Main { 5 static List<Integer> func1(List<Integer> list) { 6 try { 7 System.out.println("try"); 8 throw new RuntimeException(); 9 } 10 catch(RuntimeException e) { 11 System.out.println("catch"); 12 return list; 13 } 14 finally { 15 System.out.println("finally"); 16 list.add(42); 17 } 18 } 19 20 public static void main(String[] args) { 21 var list = new ArrayList<Integer>(List.of(1, 2, 3)); 22 23 System.out.println(list); 24 func1(list); 25 System.out.println(list); 26 } 27}

実行結果 Wandbox

[1, 2, 3] try catch finally [1, 2, 3, 42]

結果として反映されないのですが理由がわかりません。

再代入が発生しているからです。
代入前と代入後の変数valは、指し示すオブジェクトが違います。

Java

1val += 10; 2 3これは、次のように書いたのと同じ。 4 5val = val + 10;

これは先の例を少し改変しても再現できます。

Java

1import java.util.*; 2 3 4class Main { 5 static List<Integer> func1(List<Integer> list) { 6 try { 7 System.out.println("try"); 8 throw new RuntimeException(); 9 } 10 catch(RuntimeException e) { 11 System.out.println("catch"); 12 return list; 13 } 14 finally { 15 System.out.println("finally"); 16 //list.add(42); 17 list = List.of(9, 8, 7); 18 } 19 } 20 21 public static void main(String[] args) { 22 var list = new ArrayList<Integer>(List.of(1, 2, 3)); 23 24 System.out.println(list); 25 func1(list); 26 System.out.println(list); 27 } 28}

実行結果 Wandbox

[1, 2, 3] try catch finally [1, 2, 3]

まとめ

Java

1} catch(RuntimeException e) { 2 val = 10; 3 return val; // この時点で返すべきvalオブジェクトが決まっている。 4} finally { 5 val += 10; // 新しいオブジェクトを再代入しても元のオブジェクトには反映しない。 6}

変数とオブジェクトの差を意識しないとなかなか気付きづらいです。

投稿2019/07/23 10:16

編集2019/07/23 10:20
LouiS0616

総合スコア35660

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

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

退会済みユーザー

退会済みユーザー

2019/07/23 10:25

回答ありがとうございます。 再代入がされているからfinallyブロック内のvalとcatch内のvalは参照先が違うということですね! ありがとうございました!
LouiS0616

2019/07/23 10:37

ついでに。 IntegerやDouble、Stringなどの参照型は不変(immutable)ですので、同じオブジェクトは常に同じ値を保持しています。オブジェクトのフィールドだけをこっそり書き換えることはできません。 説明に際してListを持ち出したのはこの辺りの事情があったりします。
LouiS0616

2019/07/23 10:45

変数とオブジェクトの違いは、final修飾を学ぶ際にも意識しなければなりません。 頑張って下さいね。
退会済みユーザー

退会済みユーザー

2019/07/24 00:59

ご親切に色々な情報ありがとうございます。 String型がimmutableだというのは把握していましたがIntegerやDoubleまでImmutableだと思っていませんでした! ありがとうございました!
guest

0

つぎのコードを研究してみてください。

java

1package teratail; 2 3public class Kadai1203 { 4 public static void main(String[] args) { 5 int[] ary = { 0 }; 6 Integer result = sample(ary); 7 System.out.println("result=" + result + ", ary[0]=" + ary[0]); 8 } 9 10 private static Integer sample(int[] ary) { 11 int val = 0; 12 try { 13 String[] array = { "A", "B", "C" }; 14 System.out.println(array[10]); 15 System.out.println("# 1"); 16 } catch (RuntimeException e) { 17 val += 1; 18 ary[0] += 1; 19 System.out.println("# 2"); 20 return val; // <-- ここを 有効 / 無効に変化させる 21 } finally { 22 val += 10; 23 ary[0] += 10; 24 } 25 System.out.println("# 3"); 26 return val; 27 } 28}

実行例
イメージ説明

int と int[] の値の変化の差、 try 節中での return の有無での挙動の差に注目してください。

投稿2019/07/24 14:10

katoy

総合スコア22324

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

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

退会済みユーザー

退会済みユーザー

2019/07/25 00:55

katoy様ありがとうございます! 研究してみます!!
guest

0

catch節内のreturnが実行される時点で、返り値にはvalの値となってます。
その後でいくらvalを操作しようと、返り値には影響しません
この操作を反映したいなら、その操作のあとでreturn val;する必要があります

投稿2019/07/23 10:06

編集2019/07/23 10:10
y_waiwai

総合スコア87749

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

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

退会済みユーザー

退会済みユーザー

2019/07/23 10:19

回答ありがとうございます。 なぜreturnする前にfinallyブロックを仲介するのに変数が更新されないのですか? それは決まりということでしょうか? catchブロック内とfinallyブロック内のvalは同じオブジェクトを参照してるはずですよね?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問