S-JIS[2014-03-21/2016-12-17] 変更履歴
JavaのJDK1.7から1.8で互換性が無い部分の抜粋。
DecimalFormatの挙動がJDK1.8で変わった(というか正しくなった)らしい。
DecimalFormatを使ってdoubleの値を整形する場合に、JDK1.7と1.8では異なる値が返ってくることがある。
少し試した感じでは、DecimalFormatだけの違いであり、他の整形方法ではとりあえず相違なさそう?
例 | JDK1.7の実行結果 | JDK1.8の実行結果 |
---|---|---|
DecimalFormat df = new DecimalFormat(); |
0.806 |
0.805 |
BigDecimal dec = new BigDecimal("0.8055"); |
0.8055 |
0.8055 |
System.out.println(0.8055d); |
0.8055 |
0.8055 |
System.out.printf("%5.3f%n", 0.8055d); |
0.806 |
0.806 |
System.out.printf("%5.4f%n", 0.8055d); |
0.8055 |
0.8055 |
System.out.printf("%5.5f%n", 0.8055d); |
0.80550 |
0.80550 |
0.8055という値は、十進数で見ると切りのいい値だけど、浮動小数点(double)だと0.8054999…みたいな値になるらしい。
なので、それをDecimalFormatで四捨五入すると0.805になるのが正しい、ということのようだ。
Javaのバージョンが変わって出力結果が変わってしまうのは困るけれども、
そもそもそんなに厳密な結果が欲しいのであればdoubleを使っている方がおかしいから、
そんなに影響は無い気もする。
空のコレクション(Listとか)のremoveAll()およびretainAll()にnullを渡したときの挙動が変わったらしい。
例 | JDK1.7の実行結果 | JDK1.8の実行結果 |
---|---|---|
List<String> list = new ArrayList<>(); |
(特にエラーなし) | NullPointerException |
List<String> list = new ArrayList<>(); |
(特にエラーなし) | NullPointerException |
空でないコレクションだとJDK1.7でもNullPointerExceptionが発生するから、JDK1.8で統一が取れたということかな?
ジェネリクスが指定された型とRAW型(型消去されたクラス)との変換のチェックが強化されたのかな?
import java.util.List; class SampleClass { static class Baz<T> { public static List<Baz<Object>> sampleMethod(Baz<Object> param) { return null; } } private static void bar(Baz arg) { Baz element = Baz.sampleMethod(arg).get(0); } }
Bazクラスには型引数を取るように定義されているが、
barメソッドでは型引数を指定せずにBazクラスを使っている。
JDK1.7ではこれでもコンパイルは通るが、JDK1.8ではコンパイルエラーになる。
SampleClass.java:12: エラー: 不適合な型: ObjectをBazに変換できません: Baz element = Baz.sampleMethod(arg).get(0); ^
正直、細かい条件はよく分からない(爆)
例えば上記のsampleMethd()の引数を削除したメソッドにしてみると、ちゃんとコンパイル通るし。
static class Baz<T> { public static List<Baz<Object>> sampleMethod(/* Baz<Object> param */) { return null; } } private static void bar(Baz arg) { Baz element = Baz.sampleMethod(/* arg */).get(0); }
Threadのstopメソッド(Throwableが引数のもの)が使えなくなった。
具体的には、常にUnsupportedOperationExceptionをスローするようになった。
なお、引数なしのstopメソッドは従来通り使える。
が、いずれにしてもThread#stop()は非推奨メソッドだし、動作も怪しいらしいし、使っている人はいないと思うので影響は無いだろう。
apt(Annotation Processing Tool、アノテーションプロセッサー)が廃止になった。
以下のようなソースが、JDK1.7ではコンパイルが通るが、JDK1.8でコンパイルエラーになる。[2016-12-17]
これは仕様上コンパイルエラーになるのが正しく、JDK1.6でも(Eclipseでも)コンパイルエラーになるらしい。つまりJDK1.7のjavacのバグ。
public class Outer { private void same(String s) { } class Inner { public void same(int n) { } } public void run() { new Inner() { @Override public void same(int n) { } public void test() { same("abc"); // コンパイルエラー } }; } }
これがコンパイルエラーになるのは、内部クラスからメソッドを呼ぶ場合は外側クラスに同名のメソッドがあっても、内部クラスのメソッドを呼び出すので、内部クラスで定義されているメソッドと呼び出したいメソッドで引数の型が合わない為。
上の例では、内部クラスInnerのsameメソッドの引数はintなので、Stringの引数のsameメソッド(外側クラスで定義されているメソッド)は呼び出せない。
自分で試した感じでは、このバグに引っかかる(JDK1.7でコンパイルエラーにならない)のは以下の条件の場合。
ちなみに、上の例では、メソッド呼び出しを「Outer.this.same("abc")
」とすればコンパイルは通るようになる。
→無名内部クラスからアクセスできる範囲
参考: bitter_foxさんのJavaSE8リリース記念!CGに載っていないマイナーなIncompatibilityを紹介してみる