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

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

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

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

Q&A

解決済

2回答

8504閲覧

[Cannot refer to the non-final local variable target defined in an enclosing scope]の原因を教えてください。

yuji38kwmt

総合スコア437

Java

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

0グッド

0クリップ

投稿2016/06/18 05:13

編集2016/06/18 06:39

以下のJavaコードをコンパイルすると、
[Cannot refer to the non-final local variable target defined in an enclosing scope]
というエラーが発生します。

java

1package mytest.gui; 2 3import java.util.ArrayList; 4import java.util.Collection; 5import java.util.List; 6 7import org.apache.commons.collections4.CollectionUtils; 8import org.apache.commons.collections4.ListUtils; 9import org.apache.commons.collections4.Predicate; 10 11public class Console { 12 13 public static void main(String[] args) { 14 List<String> list = new ArrayList<String>(); 15 list.add("maeda"); 16 list.add("oshima"); 17 list.add("shinoda"); 18 List<String> selectedList = select(list, "shinoda"); 19 } 20 21 /** 22 * 文字列に一致するListを生成する 23 * @param list 検索対象のList 24 * @param target 絞り込み対象の文字列 25 */ 26 private static List<String> select(List<String> list, String target) { 27 return ListUtils.select(list, new Predicate<String>() { 28 public boolean evaluate(String elm) { 29 return elm.contains(target); 30 } 31 }); 32 } 33} 34

xml

1<!-- pom.xml --> 2<dependency> 3 <groupId>org.apache.commons</groupId> 4 <artifactId>commons-collections4</artifactId> 5 <version>4.0</version> 6</dependency>

エラーメッセージの通り、引数をfinal String targetにすると、エラーは出なくなりました。

英語メッセージの和訳は、「finalでないローカル変数は、エンクロージングスコープで参照できない」です。
なぜ、final修飾子を付けないと参照できないのでしょうか?

よろしくお願いします。

実行環境

  • Java7
  • Eclipse4.5
  • Commons-Collections 4.0

補足

Java8ではエラーは出ませんでした。

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

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

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

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

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

guest

回答2

0

ベストアンサー

Javaでは匿名クラス内でローカル変数を使う(クロージャの一種とされます)場合はfinalで無ければならないという言語上の制限があります。再代入を許してしまうと、矛盾が生じてしまうのが理由のようです。
参考: 内部クラスからアクセス可能なローカル変数が final でなければならない理由 - happynowの日記

また、Java 8でエラーにならなくなるのは実質的finalという新機能によって、finalをつけなくてもfinalと見なされるからです。暗黙的なfinalが付くようになっただけで、finalで無くても良くなったわけではありません。Java 8であってもfinalでなければならない制限はそのままですし、Java 8からの新機能であるラムダ式でも、実装上は匿名クラスになるため、同じくfinalで無ければならない制限は付いたままです。

投稿2016/06/18 09:31

raccy

総合スコア21735

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

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

yuji38kwmt

2016/06/18 09:45

ありがとうございます。納得できました!
guest

0

Commons-Collectionsのバージョンはどれをお使いでしょうか。

4.1では以下のコードで問題は発生せず、もちろんコンパイルエラーも発生しませんでした。
※Java8のjava.util.functions.Predicateではなく、commons-collectionsのPredicateを利用しています。

java

1import org.apache.commons.collections4.CollectionUtils; 2import org.apache.commons.collections4.Predicate; 3 4public class FilterSample { 5 6 public List<String> select(List<String> list, String target) { 7 return (List<String>) CollectionUtils.select(list, new Predicate<String>() { 8 9 @Override 10 public boolean evaluate(String elem) { 11 return elem.contains(target); 12 } 13 }); 14 } 15}

検証コード

java

1public class FilterTest { 2 3 @Test 4 public void testSelect() { 5 FilterSample sample = new FilterSample(); 6 7 List<String> list = Arrays.asList("abc","def","kjl","xyz","zab"); 8 9 List<String> result = sample.select(list, "a"); 10 11 assertTrue( result.contains("abc") ); 12 assertTrue( result.contains("zab") ); 13 assertFalse( result.contains("kjl")); 14 } 15}

投稿2016/06/18 06:26

A-pZ

総合スコア12011

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

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

yuji38kwmt

2016/06/18 06:40

すみません。Java8でなくJava7の間違いでした。Commons-Collections 4.0を使っています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問