El valor de String.valueOf

La mayoría de los desarrolladores de Java probablemente se hayan llenado de NullPointerException. La mayoría de nosotros hemos aprendido el valor de hacer ciertas cosas para reducir nuestras "oportunidades" de encontrar la NullPointerException. De hecho, hay una página Wiki dedicada a prevenir o reducir NullPointerExceptions.

Varias personas han abogado por un soporte de lenguaje adicional para un manejo mejorado y más fácil de nulos potenciales. Estos incluyen propuestas de Java SE 7, Optimized Null Check y la tesis de Kinga Dobolyi Cambiando la semántica de Java para manejar excepciones de punteros nulos.

Entre las muchas cosas que ya podemos hacer con bastante facilidad para reducir nuestros encuentros con NullPointerException, una cosa particularmente fácil de hacer es aplicar String.valueOf (Object) cuando sea apropiado. El String.valueOf(Object)método, como indica la documentación generada por Javadoc, devuelve "nulo" si el objeto pasado es nully devuelve los resultados en la Objectllamada toString () del pasado si el pasado Objectno es nulo. En otras palabras, String.valueOf(String)realiza la comprobación nula por usted.

El uso de String.valueOf(Object)es particularmente útil cuando se implementan toStringmétodos en clases personalizadas. Dado que la mayoría de las toStringimplementaciones proporcionan los miembros de datos de la clase en formato String, String.valueOf(Object)es un ajuste natural. Todos los objetos Java basados ​​en clases que extienden Object proporcionan una toString()implementación incluso si es simplemente la implementación de sus padres (o incluso Object) de toString(). Sin embargo, si una clase miembro se implementa toStringpero el miembro en sí es nulo en lugar de una instancia de la clase, entonces toString()no sirve de nada (y en realidad conduce a NullPointerExceptioncuando se llama).

Esto se demuestra con el siguiente código de ejemplo.

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); } } } 

El código anterior se puede utilizar para demostrar la construcción de un toStringmétodo en un objeto complejo y cómo se comporta cuando lo llama una clase propietaria. El método de mayor interés se encuentra al final del código que se muestra arriba. Se comentan dos valores de retorno debido a problemas asociados con ellos. El ejemplo final, el uso String.valueOf(Object)NO está comentado porque funciona mejor cada vez que se ejecuta, independientemente de que el PersonNameobjeto complejo sea ​​nulo o no . Las siguientes tres imágenes muestran el resultado de cada una de estas presentaciones de las representaciones String de los objetos Person.

Valor de cadena de objeto complejo: error en tiempo de compilación

Valor de cadena de objeto complejo toString () - NullPointerException de tiempo de ejecución potencial

Valor de cadena de objeto complejo String.valueOf () - Nulos manejados correctamente

El uso String.valueOf(Object)en toString()implementaciones puede ser especialmente beneficioso porque a menudo usamos el toString()método al depurar y lo último que necesitamos en tales casos es otra excepción encontrada al intentar ver el estado actual de nuestros datos. Por supuesto, también se pueden implementar toString()métodos con las propias comprobaciones de nulos o, mejor aún, se puede usar algo como ToStringBuilder. Sin embargo, la disponibilidad de String.valueOf(Object)es ciertamente algo que vale la pena tener en cuenta y es algo que uso con bastante frecuencia. Muchos de nosotros hemos encontrado que menos líneas de código generalmente son más claras y String.valueOf(Object)pueden ser mucho más claras que verificar explícitamente un objeto en busca de nulos antes de invocar su toString()implementación.

Finalmente, la clase String proporciona muchos métodos valueOf sobrecargados. Además de la versión que fue el foco de esta publicación de blog (acepta un Objeto), las otras versiones sobrecargadas de valueOf aceptan tipos de datos primitivos y matrices de tipos de datos primitivos.

Conclusión

Independientemente de lo que depare el futuro en términos de manejo mejorado de nulos en Java, hay muchas tácticas que podemos tomar hoy para reducir las apariciones no deseadas (¡a veces realmente queremos que se lancen!) De NullPointerException. Uno de estos es usarlo String.valueOf(Object)cuando sea apropiado.

Recursos adicionales

  • ¿String.valueOf o Integer.toString ()?
  • Llamada explícita versus implícita de toString
  • El valor de una cadena con el método String.valueOf ()
  • Convertir número en cadena

Esta historia, "El valor de String.valueOf" fue publicada originalmente por JavaWorld.