Il valore di String.valueOf

La maggior parte degli sviluppatori Java ha probabilmente avuto il pieno di NullPointerException. La maggior parte di noi ha imparato il valore di fare certe cose per ridurre le nostre "opportunità" di incontrare la NullPointerException. In effetti, esiste una pagina Wiki dedicata a prevenire o ridurre NullPointerExceptions.

Diverse persone hanno chiesto un supporto linguistico aggiuntivo per una migliore e più facile gestione del potenziale null. Questi includono le proposte Java SE 7, il controllo null ottimizzato e la tesi di Kinga Dobolyi Modifica della semantica di Java per la gestione delle eccezioni dei puntatori nulli.

Tra le tante cose che possiamo già fare piuttosto facilmente per ridurre i nostri incontri con NullPointerException, una cosa particolarmente facile da fare è applicare String.valueOf (Object) quando appropriato. Il String.valueOf(Object)metodo, come afferma la sua documentazione generata da Javadoc, restituisce "null" se l'oggetto passato è nulle restituisce i risultati sulla Objectchiamata toString () del passato se il passato Objectnon è null. In altre parole, String.valueOf(String)esegue il controllo null per te.

L'utilizzo di String.valueOf(Object)è particolarmente utile quando si implementano toStringmetodi su classi personalizzate. Poiché la maggior parte delle toStringimplementazioni fornisce i membri dei dati della classe in formato String, String.valueOf(Object)è una scelta naturale. Tutti gli oggetti Java basati su classi che estendono Object forniscono toString()un'implementazione anche se è semplicemente l' Objectimplementazione del loro genitore (o anche di) toString(). Tuttavia, se una classe membro implementa toStringma il membro stesso è null anziché un'istanza della classe, allora toString()non funziona (e in realtà porta a a NullPointerExceptionquando viene chiamato).

Ciò è dimostrato con il seguente codice di esempio.

StringHandlingExample.java

package dustin.examples; import java.io.IOException; import java.io.OutputStream; import java.util.logging.Logger; /** * Example class demonstrating use of String representations available through * implicit String, toString(), and String.valueOf(). */ public class StringHandlingExample { private static final String NEW_LINE = System.getProperty("line.separator"); /** Using java.util.logging. */ private static Logger LOGGER = Logger.getLogger( StringHandlingExample.class.getName()); /** * Main function for running tests/demonstrations. * * @param arguments Command-line arguments; none anticipated. */ public static void main(final String[] arguments) { printHeader("String representation of direct Strings", System.out); final PersonName personName = new PersonName("Flintstone", null); System.out.println("Person's Name [DIRECT]: " + personName); System.out.println("Person's Name [TOSTRING]: " + personName.toString()); System.out.println("Person's Name [STRING.VALUEOF]: " + String.valueOf(personName)); printBlankLine(System.out); printHeader("String representation of non-null complex object", System.out); final Person personOne = new Person(personName); System.out.println("Person One [DIRECT]: " + personOne); System.out.println("Person One [TOSTRING]: " + personOne.toString()); System.out.println("Person One [STRING.VALUEOF]: " + String.valueOf(personOne)); printBlankLine(System.out); printHeader("String representation of null complex object", System.out); final Person personTwo = new Person(null); System.out.println("Person Two [DIRECT]: " + personTwo); System.out.println("Person Two [TOSTRING]: " + personTwo.toString()); System.out.println("Person Two [STRING.VALUEOF]: " + String.valueOf(personTwo)); printBlankLine(System.out); } public static void printHeader(final String message, final OutputStream out) { final String headerSeparator = "===================================================================="; try { out.write((headerSeparator + NEW_LINE + message + NEW_LINE).getBytes()); out.write((headerSeparator + NEW_LINE).getBytes()); } catch (IOException ioEx) { System.out.println(headerSeparator); System.out.println(message); System.out.println(headerSeparator); LOGGER.warning("Could not write header information to provided OutputStream."); } } public static void printBlankLine(final OutputStream out) { try { out.write(NEW_LINE.getBytes()); } catch (IOException ioEx) { System.out.println(NEW_LINE); LOGGER.warning("Could not write blank line to provided OutputStream."); } } /** * Class upon which to call toString. */ private static class PersonName { private String lastName; private String firstName; public PersonName(final String newLastName, final String newFirstName) { lastName = newLastName; firstName = newFirstName; } /** * Provide String representation of me. * * @return My String representation. */ @Override public String toString() { return firstName + " " + lastName; } } private static class Person { private PersonName name; public Person(final PersonName newName) { name = newName; } /** * Provide String representation of me. * * @return My String representation. */ public String toString() { // Don't use -- leads to compiler time error (incompatible types) //return name; // Don't use -- can lead to runtime error (NullPointerException) //return name.toString(); // It's all good return String.valueOf(name); } } } 

Il codice precedente può essere utilizzato per dimostrare la costruzione di un toStringmetodo su un oggetto complesso e come si comporta quando viene chiamato da una classe proprietaria. Il metodo di maggior interesse è in fondo al codice mostrato sopra. Due valori di ritorno vengono commentati a causa di problemi ad essi associati. L'esempio finale, using String.valueOf(Object)NON è commentato perché funziona al meglio ogni volta che viene eseguito indipendentemente dal fatto che l' PersonNameoggetto complesso sia nullo o meno . Le tre immagini successive mostrano l'output per ciascuna di queste presentazioni delle rappresentazioni String degli oggetti Person.

Valore stringa da oggetto complesso - Errore in fase di compilazione

Valore stringa dall'oggetto complesso toString () - Potential Runtime NullPointerException

Valore stringa dall'oggetto complesso String.valueOf () - Null gestiti con garbo

L'utilizzo String.valueOf(Object)nelle toString()implementazioni può essere particolarmente vantaggioso perché spesso usiamo il toString()metodo durante il debug e l'ultima cosa di cui abbiamo bisogno in questi casi è un'altra eccezione incontrata durante il tentativo di vedere lo stato corrente dei nostri dati. Naturalmente, si possono anche implementare toString()metodi con i propri controlli per null o, ancora meglio, si può usare qualcosa come ToStringBuilder. Tuttavia, la disponibilità di String.valueOf(Object)è sicuramente qualcosa che vale la pena tenere a mente ed è qualcosa che mi trovo a usare abbastanza spesso. Molti di noi hanno riscontrato che un numero inferiore di righe di codice generalmente è più chiaro e String.valueOf(Object)può essere molto più chiaro rispetto al controllo esplicito di un oggetto per null prima di invocarne l' toString()implementazione.

Infine, la classe String fornisce molti metodi valueOf sovraccaricati. Oltre alla versione che era al centro di questo post del blog (accetta un oggetto), le altre versioni sovraccaricate di valueOf accettano tipi di dati primitivi e array di tipi di dati primitivi.

Conclusione

Indipendentemente da ciò che il futuro porterà in termini di miglioramento della gestione dei null in Java, ci sono molte tattiche che possiamo adottare oggi per ridurre le occorrenze indesiderate (a volte in realtà vogliamo che vengano lanciate!) Di NullPointerException. Uno di questi è da usare String.valueOf(Object)quando appropriato.

Risorse addizionali

  • String.valueOf o Integer.toString ()?
  • Chiamata esplicita e implicita di toString
  • Il valore di una stringa con il metodo String.valueOf ()
  • Converti numero in stringa

Questa storia, "The Value of String.valueOf" è stata originariamente pubblicata da JavaWorld.