2010-07-22 11 views
7

Tengo una función que devuelve un valor de int para una clave determinada (de un HashMap<String, Integer>). Si la clave no existe, quiero devolver algo que la persona que llama pueda verificar. Parece que, más comúnmente, esto sería un "devuelve -1 si la clave no existe" tipo de cosas. Sin embargo, no puedo reservar -1 para ese fin en mi caso, porque los números negativos son valores factibles para las claves que hacen existen.¿Devuelve "nulo" en la función de tipo de retorno primitivo?

Las únicas otras opciones que han sido capaces de llegar a son los siguientes:

  1. Cambiar el tipo de retorno a Integer clase contenedora y comprobar si hay null
  2. Volver algo muy poco probable, como Integer.MIN_VALUE
  3. Realice una función adicional boolean keyExists(String key) que siempre se debe llamar primero
  4. Cambie a float y use NaN en su lugar

Escribo esto en Java, pero las personas de entornos de idiomas similares pueden publicar. ¡Gracias!

+1

# 4 que es interesante . ¿Cómo verifica NaN? NaN! = NaN es verdadero. –

+1

Float.isNaN (float);) Flotador IMHO casi nunca es una buena idea. intente con long o double en su lugar. –

Respuesta

14

La primera opción es, en mi opinión, la más limpia. Los números mágicos como -1 y Integer.MIN_VALUE son un poco desordenados, especialmente cuando los valores no son intuitivos. Esa es una solución C idiomática, que los desarrolladores de Java te odiarán. Dependiendo de en qué esté usando esto, también podría arrojar una "KeyNotFoundException" si esto solo ocurre en circunstancias "excepcionales".

+2

+1 para la sugerencia de flujo excepcional –

+0

Fui con una devolución de un int, pero lanzando una excepción de tiempo de ejecución si no se encuentra la clave (entonces teniendo una función keyExists (clave)). ¿Crees que usar Integer sería una mejor solución? Probablemente sería más eficiente, porque mi HashMap ya está almacenando valores como enteros ... – idolize

+1

No ejecute una excepción de tiempo de ejecución (algo derivado de RuntimeException). Use una excepción comprobada regular. Si alguna vez desea hacer que su programa tenga varios subprocesos, tenga en cuenta que tener que llamar a una función keyExists antes de buscar el valor con dos llamadas a función crea una condición de carrera a menos que bloquee algún objeto antes de llamarlo o simplemente omita la teclaExists parte y ajusta la llamada en un bloque try/catch para KeyNotFoundException. – Hut8

1

Aunque depende en gran medida de la aplicación y las limitaciones de conocimientos, preferiría el n. ° 1 anterior. La razón es porque entonces es explícita, siempre es mejor tener una situación explícita que una implícita, como MIN_VALUE, en mi experiencia.

Otra opción es tener un objeto contenedor que contenga el valor del resultado como una primitiva int, pero también tiene un valor de estado o algo similar. Por lo que podría ser algo como:

public class Wrapper { 
    private int value = Integer.MIN_VALUE; 
    private boolean isValid; 
    // appropriate getters and setters etc. 
} 

También podría incluir una enumeración en lugar de un valor lógico de tener un estado en su lugar, dependiendo de la complejidad del problema. Si ve que este elemento contiene información compuesta (conjuntos de información con clave única, o algo similar), un objeto contenedor o un objeto de estado puede ser muy valioso en esos casos.

3

He votado por arrojar una excepción marcada aquí. En general, no me gustan las excepciones marcadas, pero parece razonable hacer algo en este caso. El caso en el que el valor no está presente deberá manejarse por separado del caso donde el valor esté presente, usar una excepción lo dejaría en claro.

En realidad, su idea de agregar un método keyExists es la mejor de las ideas que enumera, porque no se basa en que el usuario sepa que debe buscar un valor especial. Si sigue así, podría lanzar una excepción como plan de respaldo en caso de que el contenido del mapa cambie entre la llamada a keyExists y la recuperación.

+1

Creo que esta sería una muy buena solución que, de alguna manera, nunca se me pasó por la cabeza. Pero, en mi caso particular, el rendimiento sería un problema, así que creo que voy a evitar Excepciones. – idolize

+0

@mxrider: el rendimiento es un problema, ¿así que quieres evitar las excepciones? ¿Umm que? Eso me parece una "optimización" prematura/equivocada. Yo diría que escribes el código más limpio posible, luego verificas con un generador de perfiles si hay problemas reales de rendimiento con él. – Jonik

+0

Supongo que debería volver a expresarlo. Confiar en try/catch en situaciones donde el rendimiento es importante (como en un bucle o en un temporizador) puede causar un cuello de botella. De hecho, terminé requiriendo una función keyExists() para ser utilizada, y hacer que mi función getValue() arroje una RuntimeException especial si no se encuentra la clave - de esta manera no necesito try/catch, pero sigo siendo el mejor prácticas. – idolize

0

Opción 5: Iniciar una excepción

Aunque, en este caso, yo votaría por el uso de la clase Integer.

0

Creo que debería combinar las opciones n. ° 1 y n. ° 3, ya que eso es coherente con el comportamiento del HashMap subyacente. De get method documentation de HashMap:

Devuelve el valor al que la clave especificada se asigna en esta identidad mapa hash, o null si el mapa contiene ninguna asignación para esta clave. Un valor de retorno de null no necesariamente indica que el mapa no contiene ninguna asignación para la clave; también es posible que el mapa asigne explícitamente la clave a nulo. El método containsKey se puede usar para distinguir estos dos casos.

0
  1. Cambiar el tipo de retorno a la clase de contenedor entero y comprobar si hay nula.

Esta es la opción más común.

1

float no es seguro ya que no todos los valores int se pueden representar con precisión como valores int. long es una opción mejor, ya que todos los valores int se pueden almacenar de manera segura durante tanto tiempo y tendrá muchos más valores para los no encontrados.

Si está utilizando un mapa que haya un número entero objeto de todos modos ¿por qué no devolver ese (o nula)

Si realmente desea utilizar primitivas (para la eficiencia ??) le sugiero que busque en TObjectIntHashMap lugar. Esto usa valores int primitivos. Para verificar la ausencia, debe verificar containsKey() por separado.

1

dos situaciones son típicas:

  1. usted tiene una alta expectativa de encontrar un valor para una clave particular .
  2. No está seguro de si una clave en particular tiene un valor almacenado.

Si la suposición 1 es incorrecta, entonces es probable que indique un error, por lo tanto, proteja su suposición en el método de acceso con una aserción.

Si aplica 2, ¿cómo estarás seguro de lo que se devuelve? así que proporcione un método de prueba como "keyExists" y sepa absolutamente antes de acceder al mapa.

En el caso 1, no se requiere ninguna comprobación, que es mucho más limpia, pero el acceso fallará si se equivoca. Con casos especiales como -1 o Integer.MIN_VALUE, es muy difícil estar seguro de que no se utilizarán.

Lenguajes como Haskell, Scala y C# tienen tipos especiales de transmitir presencia/ausencia de un valor que es mucho mejor que el uso de nulo (si se olvida de probar es probable que obtener una NullPointerException)

Cuestiones relacionadas