ClassCastExceptionをスローする代わりに、型キャストでnull値を返すことが実際的である状況があります。 C#には、これを行うためのas
演算子があります。 Javaで利用可能な同等のものがあるので、ClassCastExceptionを明示的にチェックする必要はありませんか?
@Omar Koohejiによって提案されたasの実装は次のとおりです。
public static <T> T as(Class<T> clazz, Object o){
if(clazz.isInstance(o)){
return clazz.cast(o);
}
return null;
}
as(A.class, new Object()) --> null
as(B.class, new B()) --> B
私はあなたがあなた自身を転がさなければならないと思うでしょう:
return (x instanceof Foo) ? (Foo) x : null;
編集:クライアントコードでヌルを処理したくない場合は、 Null Object を導入できます
interface Foo {
public void doBar();
}
class NullFoo implements Foo {
public void doBar() {} // do nothing
}
class FooUtils {
public static Foo asFoo(Object o) {
return (o instanceof Foo) ? (Foo) o : new NullFoo();
}
}
class Client {
public void process() {
Object o = ...;
Foo foo = FooUtils.asFoo(o);
foo.doBar(); // don't need to check for null in client
}
}
C#のinstanceof
の代わりにis
キーワードを使用できますが、as
のようなものはありません。
例:
if(myThing instanceof Foo) {
Foo myFoo = (Foo)myThing; //Never throws ClassCastException
...
}
このような静的ユーティリティメソッドを作成できます。私はそれがひどく読みやすいとは思わないが、それはあなたがやろうとしていることの最善の近似である。静的インポートを使用すると、読みやすさの点でそれほど悪くはありません。
package com.stackoverflow.examples;
public class Utils {
@SuppressWarnings("unchecked")
public static <T> T safeCast(Object obj, Class<T> type) {
if (type.isInstance(obj)) {
return (T) obj;
}
return null;
}
}
これがどのように機能するか(そして機能するか)を示すテストケースです。
package com.stackoverflow.examples;
import static com.stackoverflow.examples.Utils.safeCast;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import org.junit.Test;
public class UtilsTest {
@Test
public void happyPath() {
Object x = "abc";
String y = safeCast(x, String.class);
assertNotNull(y);
}
@Test
public void castToSubclassShouldFail() {
Object x = new Object();
String y = safeCast(x, String.class);
assertNull(y);
}
@Test
public void castToUnrelatedTypeShouldFail() {
Object x = "abc";
Integer y = safeCast(x, Integer.class);
assertNull(y);
}
}
Java 8では、オプションでストリーム構文を使用することもできます:
Object o = new Integer(1);
Optional.ofNullable(o)
.filter(Number.class::isInstance)
.map(Number.class::cast)
.ifPresent(n -> System.out.print("o is a number"));