Evitando ponteiro nulo quando o valor único precisa ser retornado

Em primeiro lugar, há um monte de perguntas sobre stackoverflow em ponteiros nulos - mas não consegui encontrar este. Ela existia e eu não a encontrei, por favor, poupe meu erro.

A questão é genérica - se uma função retorna apenas um elemento, então como lidar com o caso 'elemento' ausente. Por exemplo: o código de amostra é apenas uma amostra.

public int findSmallestNumberGreaterThanX(int a[], int x) {
 //do what ever logic.
  if (numFound) { return smallesNumberGreaterThanX; }
  else {
    //what ??
   }
}

Se não houvesse nenhum número na matriz maior que x - o que fazer?

  1. O java efetivo menciona return array vazio ao invés de null pointer - mas vale a pena criar um array se a função retornar um único elemento?

  2. A próxima opção é retornar null. Eu vi um monte de posts que rejeitam a idéia de retornar null.

  3. Terceiro é retornar um objeto {booleano encontrado; int valor; }. Isso soa como um exagero.

Por favor, sugira-me uma melhor abordagem aqui.

3
Afirmei todas as opções exploradas em outras questões sobre estouro de pilha. Parece haver respostas mistas - nenhuma abordando diretamente esse cenário específico - desculpas, mas não chegou a nenhuma conclusão.
adicionado o autor JavaDeveloper, fonte
O smallesNumberGreaterThanX incluirá x em qualquer condição?
adicionado o autor Vishal K, fonte
adicionado o autor Elazar, fonte

7 Respostas

Depende do que sua função retorna. Se retornar um valor, então qualquer valor é válido, portanto, o valor de retorno não pode ser usado para o controle de validade.

Se você retornar o índice do valor encontrado na matriz, qualquer coisa abaixo de zero poderá ser considerada como valor ilegal e poderá ser usada para o código de erro.

Talvez você possa adicionar um parâmetro que contenha seu valor de retorno e alterar sua função para que ele retorne um booleano indicando se o número foi encontrado ou não

3
adicionado

Se sua comparação for estrita, você poderá retornar Integer.MIN_VALUE, pois é o único valor que não pode ser retornado de outra maneira. (como é menor que todos os outros valores, exceto ele mesmo).

3
adicionado
Nesse caso, Integer.MIN_VALUE está atuando como um valor "sentinel".
adicionado o autor Raedwald, fonte
e se x == Integer.MIN_VALUE?
adicionado o autor Elazar, fonte
+1, mas você deve explicar por que essa opção é a melhor, em vez das outras opções mencionadas na pergunta.
adicionado o autor Vulcan, fonte

Eu vejo várias maneiras de resolver esse problema. Eu recomendo usar (1) ou (2) e evitando (3) e (4).

(1): lance uma exceção. Seu método ficaria assim:

public int findSmallestNumberGreaterThanX(int a[], int x)
    throws NoSuchNumberException {
 //do what ever logic.
  if (numFound) { return smallestNumberGreaterThanX; }
  else {
    throw new NoSuchNumberException();
   }
}

e seria chamado dizendo

try {
  int smallestNum = findSmallestNumberGreaterThanX(a, x);
  //use smallestNum
} catch(NoSuchNumberException e) {
  //handle case where there is no smallestNum
}

Você também teria que criar a classe NoSuchNumberException:

public class NoSuchNumberException extends Exception {

  public NoSuchNumberException() {}

  public NoSuchNumberException(String message) {
    super(message);
  }
}


(2): Slightly refactor your code.

Em vez de fazer tudo em um método, faça o método

public int findSmallestNumber(int a[]) {...}

e depois diga

int smallestNum = findSmallestNumber(a);
if (smallestNum > x) {
  //use smallestNum
} else {
  //handle case where there is no smallestNum > x
}


(3): Set your return type to Integer, and return null. Java will automatically cast between int and Integer, and null is a valid value for Integer. Just be sure to check for null wherever you use this method, because if you try to cast null to an int, it will break.


(4): return a number less than x. (I strongly recommend you do not use this solution unless you can also use that number somehow.) Since the number is less than x, it can be identified as an error condition.

3
adicionado
Obrigado - mas qual das opções é mais recomendada .. em um caso genérico, um elemento 'que poderia ser um único objeto, um float, qualquer coisa que não é uma coleção' precisa ser retornado? Eu
adicionado o autor JavaDeveloper, fonte
Às vezes não há nenhum método padrão, do ponto de vista estrutural eu gosto da exceção mais (não há números mágicos especiais) mas as exceções são muito caras, então na prática eu costumo usar w -1 ou null (dependendo de se retornar um primitivo ou um objeto)
adicionado o autor Richard Tingle, fonte
@JavaDeveloper Eu diria que (1) ou (2) seria recomendado. Não há necessariamente uma 'resposta certa' ao estruturar um programa. Mas se você está projetando um método genérico que pode retornar qualquer coisa, você pode querer reconsiderar isso. A saída seria inutilizável a menos que você saiba exatamente o que é (ou a menos que você use muitos exemplos de instruções, mas isso é geralmente menosprezado.) Embora se você realmente quiser, pode simplesmente retornar Object.
adicionado o autor Martin Wickham, fonte

Outra solução ainda não mencionada é ter uma classe especial representeo valores com falhas. Em um de nossos projetos, tivemos

public interface Option
    extends java.util.Collection
{
   //Throws an exception if empty.
    public T get();
   //Returns `deflt` if empty.
    public T getOrElse(T deflt);
    public boolean isEmpty();
}

Option represents either a single value of type T or no value. (It implements Collection so that it can be viewed as a collection of 0 or 1 elements, which allows you to use it for example in for comprehensions, but it's probably not important for your case.) It had two subclasses, one representing an empty Option e one representing a full one:

// ---

public final class None
    extends AbstractCollection
    implements Option
{
    public None() {}
   //...
}

e

public final class Some
    extends AbstractCollection
    implements Option
{
    private final T value;

    public Some(T value) {
        this.value = value;
    }

   //...
}

Código completo disponível aqui . É apenas uma variante da classe Option do Scala.

No seu caso, você o usaria como

public Option findSmallestNumberGreaterThanX(int a[], int x) {
 //do what ever logic.
  if (numFound) { return new Some(smallesNumberGreaterThanX); }
  else { return new None(); }
}

Creating such an object has negligible overhead (unless you create millions of them), e gives a nice semantic distinction between a successful e a failed operation.

2
adicionado
Soa bem..mas como é muito diferente da opção 3? Terceiro é retornar um objeto {booleano encontrado; int valor; }. Isso soa como um exagero. Em vez de interface e 2 classes eu apenas retornaria uma única classe?
adicionado o autor JavaDeveloper, fonte
@JavaDeveloper É similar, você poderia implementar a Opção internamente como você sugere. Essa variante é polimórfica, portanto, você pode usá-la para qualquer finalidade. Não é nada demais - os detalhes da implementação não são tão importantes, o que importa no final é a clareza do código. Se você evitar null se usar Option <...> , sempre estará claro quais valores são opcionais e quais valores são necessários. Aqui é um bom tutorial para a Opção do Scala.
adicionado o autor Petr Pudlák, fonte

Há mais uma solução ainda não mencionada:

Instead of returning the element itself, return its index. If there is no such element, either return -1 or the array size. This approach is quite common in C++ with iterators.

2
adicionado

Se o smallesNumberGreaterThanX não incluir o x , você poderá usar algo assim:

public int findSmallestNumberGreaterThanX(int a[], int x) {
 //do what ever logic.
  if (numFound) { return smallesNumberGreaterThanX; }
  else {
     return x;
   }
}

E enquanto você chama o método, ele pode ser usado assim:

int var = findSmallestNumberGreaterThanX(a ,x);
if (var == x)
{
    System.out.println("No value found");
}
2
adicionado
Esta não é uma solução válida se x for igual a Integer.MIN_VALUE
adicionado o autor sasha.sochka, fonte

É muito comum retornar null para um resultado "não encontrado". Retornar um valor "especial", como Integer.MIN_VALUE é OK, porque matematicamente esse não é um resultado legítimo, mas seria uma abordagem não convencional para o chamador lidar.

Você tem duas opções:

  1. Lance uma exceção se não for encontrado
  2. Altere o tipo de retorno para um tipo de objeto e retorne nulo

Opção 1. geralmente não é uma boa idéia, mas se você absolutamente deve retornar um int então use-o

A opção 2. é a solução mais comum, documentada com javadoc

/**
 * @returns null if not found
 */
public Integer findSmallestNumberGreaterThanX(int a[], int x) {
   //do what ever logic.
    if (numFound)
        return smallesNumberGreaterThanX;
    return null;
}
0
adicionado
@DonRoby oops! Depois de toda essa conversa, esqueci de fazer a mudança mais importante. Corrigido agora. obrigado
adicionado o autor Bohemian, fonte
Você pode querer alterar int para Integer em seu código de exemplo, conforme indicado no texto de resposta.
adicionado o autor Don Roby, fonte