Java "?"Operador para verificar null - O que é? Ternary, Não!)

Estava a ler um artigo ligado a uma história de slashdot, e deparei-me com esta pequena notícia:

pegue a última versão de Java, que tenta fazer a verificação do ponteiro nulo mais fácil, oferecendo sintaxe estenográfica para os testes intermináveis de ponteiros. Apenas adicionar um ponto de interrogação a cada método a invocação inclui automaticamente um ensaio para ponteiros nulos, substituindo um o ninho de ratos de "se-then statements", tais como: {[0]}

com isto: {[1]}

Pesquisei na internet (OK, passei pelo menos 15 minutos pesquisando variações no Google sobre "Java question mark") e não consegui nada. Então, a minha pergunta: Existe alguma documentação oficial sobre isto? Eu descobri que c# tem um operador similar (o "??"operator), mas eu gostaria de obter a documentação para o idioma em que estou trabalhando. Ou, isto é apenas um uso do operador ternário que nunca vi antes.

Obrigado!

editar: ligação ao artigo: http://infoworld.com/d/developer-world/12-programming-mistakes-avoid-292

Author: Erty Seidohl, 2010-12-08

13 answers

A ideia original vem de groovy. Foi proposto para Java 7 como parte do projeto Coin: https://wiki.openjdk.java.net/display/Coin/2009+Proposals+TOC (Elvis and Other Null-Safe Operators), but hasn't been accepted yet. O operador do Elvis?: was proposed to make x ?: y shorthand for x != null ? x : y, especially useful when x is a complex expression.
 65
Author: ataylor, 2016-01-07 20:02:41

Esta sintaxe não existe em Java, nem está prevista para ser incluída em nenhuma das próximas versões que eu saiba.

 48
Author: ColinD, 2010-12-08 17:09:01

Havia uma proposta para ele em Java 7, mas foi rejeitada:

Http://tech.puredanger.com/java7/#null

 16
Author: PaulJWilliams, 2010-12-08 17:06:33
Uma maneira de resolver a falta de "?"operador que utiliza Java 8 sem a sobrecarga de try-catch (que também poderia esconder um NullPointerException originado em outro lugar, como mencionado) é criar uma classe para "pipe" métodos em um estilo Java-8-Stream.
public class Pipe<T> {
    private T object;

    private Pipe(T t) {
        object = t;
    }

    public static<T> Pipe<T> of(T t) {
        return new Pipe<>(t);
    }

    public <S> Pipe<S> after(Function<? super T, ? extends S> plumber) {
        return new Pipe<>(object == null ? null : plumber.apply(object));
    }

    public T get() {
        return object;
    }

    public T orElse(T other) {
        return object == null ? other : object;
    }
}

Então, o exemplo dado tornar-se-ia:

public String getFirstName(Person person) {
    return Pipe.of(person).after(Person::getName).after(Name::getGivenName).get();
}

[EDITAR]

Depois de pensar mais, descobri que é realmente possível alcançar o mesmo somente usando classes padrão Java 8:

public String getFirstName(Person person) {
    return Optional.ofNullable(person).map(Person::getName).map(Name::getGivenName).orElse(null);
}

Neste case, é mesmo possível escolher um valor padrão (como "<no first name>") em vez de null passando-o como parâmetro de orElse.

 13
Author: Helder Pereira, 2017-06-20 06:56:47

Ver: https://blogs.oracle.com/darcy/project-coin:-the-final-five-or-so (especificamente "Elvis and other null safe operators").

O resultado é que este recurso foi considerado para Java 7, mas não foi incluído.

 7
Author: Darron, 2017-11-09 21:44:12
Na verdade, é o operador de dereferência segura do Groovy. Você não pode usá-lo em Java puro (infelizmente), de modo que o post é simplesmente errado (ou mais provavelmente ligeiramente enganador, se ele está alegando Groovy para ser a "última versão de Java").
 6
Author: Andrzej Doyle, 2017-11-09 21:58:59

É possível definir métodos util que resolvam isso de uma forma quase bonita com Java 8 lambda.

Esta é uma variação da solução H-MANs mas usa métodos sobrecarregados com vários argumentos para lidar com vários passos em vez de capturar NullPointerException.

Mesmo que eu ache que esta solução é fixe, acho que prefiro Os segundos de Helder Pereira {[[7]} uma vez que isso não requer nenhum método util.

void example() {
    Entry entry = new Entry();
    // This is the same as H-MANs solution 
    Person person = getNullsafe(entry, e -> e.getPerson());    
    // Get object in several steps
    String givenName = getNullsafe(entry, e -> e.getPerson(), p -> p.getName(), n -> n.getGivenName());
    // Call void methods
    doNullsafe(entry, e -> e.getPerson(), p -> p.getName(), n -> n.nameIt());        
}

/** Return result of call to f1 with o1 if it is non-null, otherwise return null. */
public static <R, T1> R getNullsafe(T1 o1, Function<T1, R> f1) {
    if (o1 != null) return f1.apply(o1);
    return null; 
}

public static <R, T0, T1> R getNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, R> f2) {
    return getNullsafe(getNullsafe(o0, f1), f2);
}

public static <R, T0, T1, T2> R getNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, T2> f2, Function<T2, R> f3) {
    return getNullsafe(getNullsafe(o0, f1, f2), f3);
}


/** Call consumer f1 with o1 if it is non-null, otherwise do nothing. */
public static <T1> void doNullsafe(T1 o1, Consumer<T1> f1) {
    if (o1 != null) f1.accept(o1);
}

public static <T0, T1> void doNullsafe(T0 o0, Function<T0, T1> f1, Consumer<T1> f2) {
    doNullsafe(getNullsafe(o0, f1), f2);
}

public static <T0, T1, T2> void doNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, T2> f2, Consumer<T2> f3) {
    doNullsafe(getNullsafe(o0, f1, f2), f3);
}


class Entry {
    Person getPerson() { return null; }
}

class Person {
    Name getName() { return null; }
}

class Name {
    void nameIt() {}
    String getGivenName() { return null; }
}
 2
Author: Lii, 2015-11-17 17:35:55

Não tenho a certeza se isto sequer funcionaria; se, digamos, a referência da pessoa fosse nula, qual seria o tempo de execução que a substituiria? Uma nova pessoa? Isso exigiria que a pessoa tivesse alguma inicialização padrão que você esperaria neste caso. Você pode evitar exceções de referência nula, mas você ainda teria um comportamento imprevisível se você não planejasse este tipo de Configurações.

O quê?? operador em C# pode ser melhor chamado o operador "coalesce"; você pode cadeia várias expressões e ele irá devolve o primeiro que não for nulo. Infelizmente, Java não o tem. Eu acho que o melhor que você poderia fazer é usar o operador ternário para realizar verificações nulas e avaliar uma alternativa à expressão inteira se qualquer membro da cadeia é nula:
return person == null ? "" 
    : person.getName() == null ? "" 
        : person.getName().getGivenName();

Também te dava jeito tentar apanhar:

try
{
   return person.getName().getGivenName();
}
catch(NullReferenceException)
{
   return "";
}
 1
Author: KeithS, 2010-12-22 18:57:15
Aqui está, invocação null-safe em Java 8:
public void someMethod() {
    String userName = nullIfAbsent(new Order(), t -> t.getAccount().getUser()
        .getName());
}

static <T, R> R nullIfAbsent(T t, Function<T, R> funct) {
    try {
        return funct.apply(t);
    } catch (NullPointerException e) {
        return null;
    }
}
 0
Author: H-MAN, 2014-03-20 20:49:35

Se alguém está à procura de uma alternativa para versões java antigas, pode tentar esta que eu escrevi:

/**
 * Strong typed Lambda to return NULL or DEFAULT VALUES instead of runtime errors. 
 * if you override the defaultValue method, if the execution result was null it will be used in place
 * 
 * 
 * Sample:
 * 
 * It won't throw a NullPointerException but null.
 * <pre>
 * {@code
 *  new RuntimeExceptionHandlerLambda<String> () {
 *      @Override
 *      public String evaluate() {
 *          String x = null;
 *          return x.trim();
 *      }  
 *  }.get();
 * }
 * <pre>
 * 
 * 
 * @author Robson_Farias
 *
 */

public abstract class RuntimeExceptionHandlerLambda<T> {

    private T result;

    private RuntimeException exception;

    public abstract T evaluate();

    public RuntimeException getException() {
        return exception;
    }

    public boolean hasException() {
        return exception != null;
    }

    public T defaultValue() {
        return result;
    }

    public T get() {
        try {
            result = evaluate();
        } catch (RuntimeException runtimeException) {
            exception = runtimeException;
        }
        return result == null ? defaultValue() : result;
    }

}
 0
Author: irobson, 2015-11-18 20:49:05

Você pode testar o código que você forneceu e ele vai dar sintaxe error.So, não é suportado em Java. Groovy o suporta e foi proposto para Java 7 (mas nunca foi incluído).

No entanto, você pode usar o opcional fornecido em Java 8. Isto pode ajudá-lo a alcançar algo semelhante linha. https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html

Exemplo de código facultativo

 0
Author: SK -, 2017-11-29 18:55:26

Java não tem a sintaxe exata mas a partir de JDK-8, temos a API opcional com vários métodos à nossa disposição. Assim, a versão c# com o uso de operador condicional nulo:

return person?.getName()?.getGivenName(); 

Pode ser escrito da seguinte forma em Java com a API opcional :

 return Optional.ofNullable(person)
                .map(e -> e.getName())
                .map(e -> e.getGivenName())
                .orElse(null);

Se algum dos person, getName ou getGivenName é nulo e depois nulo é devolvido.

 0
Author: Aomine, 2018-06-10 15:17:15
 -3
Author: Peter Lawrey, 2010-12-08 17:48:19