long
からint
へのキャストで情報が失われないことを確認するための、Javaで最も慣用的な方法は何ですか?
これが私の現在の実装です。
public static int safeLongToInt(long l) {
int i = (int)l;
if ((long)i != l) {
throw new IllegalArgumentException(l + " cannot be cast to int without changing its value.");
}
return i;
}
そうするために、新しいメソッドが Java 8 で追加されました。
import static Java.lang.Math.toIntExact;
long foo = 10L;
int bar = toIntExact(foo);
オーバーフローの場合はArithmeticException
をスローします。
参照してください: Math.toIntExact(long)
Java 8には、他にもいくつかのオーバーフローセーフメソッドが追加されています。それらは、exactで終わります。
例:
Math.incrementExact(long)
Math.subtractExact(long, long)
Math.decrementExact(long)
Math.negateExact(long),
Math.subtractExact(int, int)
私は私がそれをするのと同じくらい単純にそれをすると思います:
public static int safeLongToInt(long l) {
if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) {
throw new IllegalArgumentException
(l + " cannot be cast to int without changing its value.");
}
return (int) l;
}
私はそれが繰り返しキャスティングよりも明確に意図を表現していると思いますが…それはやや主観的です。
潜在的な関心事のメモ - C#ではそれはただのようになります。
return checked ((int) l);
Google Guavaの Ints クラスを使用すると、メソッドを次のように変更できます。
public static int safeLongToInt(long l) {
return Ints.checkedCast(l);
}
リンクされたドキュメントから:
checkedCast
public static int checkedCast(long value)
可能であれば、
value
と等しいint値を返します。パラメーター:
value
-int
型の範囲内の任意の値戻り値:
int
と等しいvalue
値例外:
IllegalArgumentException
-value
がInteger.MAX_VALUE
より大きい、またはInteger.MIN_VALUE
より小さい場合
ちなみに、safeLongToInt
ラッパーは、もちろん大規模なリファクタリングを行わずに機能を変更するために残しておきたいのでなければ必要ありません。
BigDecimalの場合:
long aLong = ...;
int anInt = new BigDecimal(aLong).intValueExact(); // throws ArithmeticException
// if outside bounds
それが必要とされるよりも大きい場合にあなたが価値を気にしない場合のために、ここに解決策があります;)
public static int safeLongToInt(long l) {
return (int) Math.max(Math.min(Integer.MAX_VALUE, l), Integer.MIN_VALUE);
}
いけません:これは解決策ではありません!
私の最初のアプローチは次のとおりです。
public int longToInt(long theLongOne) {
return Long.valueOf(theLongOne).intValue();
}
しかし、それは単にlongをintにキャストするだけで、潜在的に新しいLong
インスタンスを作成するか、またはLongプールからそれらを取得します。
欠点
数値がLong
のプール範囲内にない場合、Long.valueOf
は新しいLong
インスタンスを作成します[-128、127]。
intValue
の実装は以下のことしかしません:
return (int)value;
したがって、これは単にlong
をint
にキャストするよりもさらに悪いと考えることができます。
値をキャストして値が変わったかどうかを確認する明らかな方法は、キャストして結果を確認することであると私は主張します。ただし、比較するときは、不要なキャストを削除します。私はまた、一文字の変数名にもそれほど熱心ではありません(例外x
とy
。
public static int intValue(long value) {
int valueInt = (int)value;
if (valueInt != value) {
throw new IllegalArgumentException(
"The long value "+value+" is not within range of the int type"
);
}
return valueInt;
}
しかし、可能であれば、実際にはこの変換を避けたいと思います。明らかに不可能なこともありますが、そのような場合、IllegalArgumentException
はクライアントコードに関する限り投げているのはほぼ間違いなく間違った例外です。
Java整数型は符号付きとして表されます。 2の間の入力で31 と232 (または-231 と-232)キャストは成功しますが、テストは失敗します。
確認する必要があるのは、long
のすべての上位ビットがすべて同じかどうかです。
public static final long LONG_HIGH_BITS = 0xFFFFFFFF80000000L;
public static int safeLongToInt(long l) {
if ((l & LONG_HIGH_BITS) == 0 || (l & LONG_HIGH_BITS) == LONG_HIGH_BITS) {
return (int) l;
} else {
throw new IllegalArgumentException("...");
}
}
(int) (longType + 0)
しかし、Longは最大値を超えることはできません:)