2010-07-22 13 views
7

Ho una funzione che restituisce un valore int per una determinata chiave (da HashMap<String, Integer>). Se la chiave non esiste, voglio restituire qualcosa che il chiamante può verificare. Sembra che, più comunemente, questo sarebbe un "restituisce -1 se la chiave non esiste" tipo di cosa. Tuttavia, non posso prenotare -1 per questo scopo nel mio caso, perché i numeri negativi sono valori possibili per le chiavi che esistono .Restituisce "null" sulla funzione di tipo ritorno primitivo?

Le uniche altre opzioni che sono stati in grado di elaborare sono i seguenti:

  1. Cambia il tipo di ritorno alla Integer classe wrapper e verificare la presenza di null
  2. ritorno qualcosa di molto improbabile, come ad esempio Integer.MIN_VALUE
  3. Creare una funzione aggiuntiva che deve essere sempre chiamata prima
  4. Passare a float e utilizzare NaN invece

Sto scrivendo questo in Java, ma le persone provenienti da ambienti linguistici simili sono invitati a postare. Grazie!

+1

# 4 è interessante . Come controlli NaN? NaN! = NaN è vero. –

+1

Float.isNaN (float);) IMHO float non è quasi mai una buona idea. prova invece a lungo o doppio. –

risposta

14

La prima opzione è, a mio parere, la più pulita. I numeri magici come -1 e Integer.MIN_VALUE sono piuttosto disordinati, specialmente quando i valori non sono intuitivi. Questa è una soluzione C idioma, che gli sviluppatori Java ti odieranno. A seconda di ciò che stai effettivamente usando per te potresti anche lanciare un "KeyNotFoundException" se questo accade solo in circostanze "eccezionali".

+2

+1 per il suggerimento di flusso eccezionale –

+0

Sono andato con un ritorno di un int, ma lanciando un'eccezione di runtime se la chiave non è stata trovata (avendo quindi una funzione keyExists (chiave)). Pensi che l'utilizzo di Integer sarebbe una soluzione migliore? Probabilmente sarebbe più efficiente, perché la mia HashMap sta già memorizzando valori come Integers ... – idolize

+1

Non lanciare un'eccezione di runtime (qualcosa derivata da RuntimeException). Usa un'eccezione regolare controllata. Se vuoi rendere il tuo programma multi-thread, tieni presente che dover chiamare una funzione keyExists prima di cercare il valore con due chiamate a funzione separate crea una race condition a meno che non blocchi un oggetto prima di chiamarlo ogni volta o semplicemente omettere la parte keyExists e avvolgere la chiamata in un blocco try/catch per KeyNotFoundException. – Hut8

1

Anche se dipende fortemente dall'applicazione e conosce i vincoli, preferirei il primo. Il motivo è perché allora è esplicito - è sempre meglio avere una situazione esplicita di una implicita - come MIN_VALUE - nella mia esperienza.

Un'altra opzione consiste nell'avere un oggetto wrapper che contiene il valore del risultato come int primitivo, ma ha anche un valore di stato o qualcosa di simile. Quindi potrebbe essere qualcosa di simile:

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

Si potrebbe includere anche un enum invece di un valore booleano per avere uno stato, invece, a seconda della complessità del problema. Se vedi questo elemento contenente informazioni composite - set di informazioni con chiave di singole chiavi, o qualcosa di simile - un oggetto contenitore o un oggetto di stato può essere molto utile in questi casi.

3

Io voto per lanciare un'eccezione controllata qui. Generalmente non mi piacciono le eccezioni controllate, ma in questo caso sembra una cosa ragionevole da fare. Il caso in cui il valore non è presente dovrà essere gestito separatamente dal caso in cui il valore è presente, utilizzando un'eccezione lo renderebbe chiaro.

In realtà la tua idea di aggiungere un metodo keyExists è la migliore delle idee che elencherai, perché non si basa sull'utente che sa di cercare un valore speciale. Se si va in questo modo, si potrebbe generare un'eccezione come piano di backup nel caso in cui il contenuto della mappa cambi tra la chiamata a keyExists e il recupero.

+1

Penso che questa sarebbe una soluzione davvero buona che, in qualche modo, non mi è mai passata per la testa. Ma, nel mio caso particolare, le prestazioni sarebbero un po 'problematiche quindi penso che eviterò Eccezioni. – idolize

+0

@mxrider: le prestazioni sono un problema, quindi si desidera evitare le eccezioni? Umm, cosa? Sembra un'ottimizzazione prematura/sbagliata per me. Direi di scrivere il codice più pulito possibile, quindi controllare con un profiler se ci sono problemi di prestazioni reali con esso. – Jonik

+0

Suppongo che dovrei riformulare. Affidarsi a try/catch in situazioni in cui le prestazioni sono importanti (ad esempio in un loop o su un timer) può causare un collo di bottiglia. In realtà ho finito per richiedere una funzione keyExists() da utilizzare e la mia funzione getValue() lanciava una RuntimeException speciale se la chiave non viene trovata - in questo modo non ho bisogno di try/catch, ma sto ancora seguendo il meglio pratiche. – idolize

0

Opzione 5: Tira un eccezione

Anche se, in questo caso, avrei votato per utilizzando la classe Integer.

0

Penso che dovresti combinare le opzioni 1 e 3, poiché ciò è coerente con il comportamento della HashMap sottostante. Da get method documentation di HashMap:

Restituisce il valore al quale la chiave specificata è mappato in questa identità mappa di hash, o null se la mappa non contiene la mappatura per questa chiave. Un valore di ritorno di null non indica necessariamente che la mappa non contiene alcuna mappatura per la chiave; è anche possibile che la mappa associ esplicitamente la chiave a null. Il metodo containsKey può essere usato per distinguere questi due casi.

0
  1. Cambiare tipo di ritorno di Integer classe wrapper e controllare nulla.

Questa è l'opzione più comune.

1

float non è sicuro in quanto non tutti i valori int possono essere precisi rappresentati come valori int. lunga è un'opzione migliore in quanto tutti i valori int possono essere archiviati in sicurezza a lungo e si avranno molti più valori per i non-trovati.

Se si utilizza una mappa si dispone di un intero oggetto in ogni caso, quindi perché non tornare che (o nullo)

Se davvero si vuole utilizzare primitive (per l'efficienza ??) Io suggerisco di guardare TObjectIntHashMap invece. Questo utilizza valori int primitivi. Per verificare l'assenza, è necessario selezionare containsKey() separatamente.

1

due situazioni sono tipiche:

  1. avete un'alta aspettativa di trovare un valore per un particolare chiave.
  2. Non si è sicuri se un particolare tasto ha un valore memorizzato.

Se l'ipotesi 1 è errata, è probabile che indichi un bug, quindi proteggi la tua ipotesi nel metodo di accesso con un'asserzione.

Se si applica 2, come si sarà sicuri di ciò che viene restituito? quindi fornisci un metodo di prova come "keyExists" e conosci assolutamente prima di accedere alla mappa.

Nel caso 1, non è richiesto alcun controllo, che è molto più pulito, ma l'accesso avrà esito negativo se si è in errore. Con casi speciali come -1 o Integer.MIN_VALUE è molto difficile essere sicuri che non vengano utilizzati.

Lingue come Haskell, Scala e C# hanno particolari tipi di trasmettere presenza/assenza di un valore che è di gran lunga migliore di quanto l'uso di null (se si dimentica di testare è probabile ottenere un NullPointerException)

Problemi correlati