2008-09-29 3 views
42

Бывают ситуации, когда практично иметь тип-cast, возвращающий нулевое значение вместо того, чтобы бросать исключение ClassCastException. Для этого C# имеет оператор as. Есть ли что-то эквивалентное в Java, поэтому вам не нужно явно проверять ClassCastException?Как эмулировать C# as-operator в Java

ответ

47

Вот реализация, как, как это было предложено @Omar Kooheji:

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 
13

Вы можете использовать ключевое слово instanceof вместо C# is, но ничего подобного as.

Пример:

if(myThing instanceof Foo) { 
    Foo myFoo = (Foo)myThing; //Never throws ClassCastException 
    ... 
} 
+9

Да, старый двойной литой. У позора Java нет такого элегантного, как оператор «как». – 2008-09-29 14:14:59

+1

«как» - очень полезная вещь. – 2008-09-29 14:16:03

25

Я думаю, что вам придется свернуть свой собственный:

return (x instanceof Foo) ? (Foo) x : null; 

EDIT: Если вы не хотите, чтобы ваш кода клиента, чтобы иметь дело с нулями, то вы можете ввести 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 
    } 
} 
-2

Я спекулировать можно Propably creas как оператор

что-то вроде

as<T,Type> (left, right) 
which evaluates to 
if (typeof(left) == right) 
    return (right)left 
else 
    return null 

Я не знаю, как вы могли бы сделать это, я с # на данный момент, и моя Java шляпа получила немного пыльный, так как я покинул университет.

+1

Сравнение конкретного типа, т. Е. `Typeof (left) == right` не является тем, что` как`. – weston 2013-09-06 08:31:02

10

Вы можете написать статический метод утилиты, подобный этому. Я не думаю, что это ужасно читаемо, но это лучшее приближение того, что вы пытаетесь сделать. И если вы используете статический импорт, это будет не так уж плохо с точки зрения удобочитаемости.

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); 
    } 
} 
+0

Это не работает. isAssignable Из тестов, чтобы проверить, является ли obj экземпляром суперкласса T. Таким образом, safeCast (новый Object(), A.class) .doA() вернет исключение класса cast, а не NPE. – 2008-09-29 14:43:40

0

В 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"));