java string

java - ¿Debería preinicializar una variable que se sobrescribe en varias ramas?



string (8)

Hay un método:

private String myMethod(String gender) { String newString = ""; if(gender.equals("a")) newString = internal.getValue(); else newString = external.getValue(); return newString; }

Refactoré todo, pero con un pequeño cambio: String newString; en lugar de: String newString = "";

¿Este refactor mejora el código? Sé que String es null cuando no lo inicializamos, pero en este ejemplo siempre tendrá un valor de from if o else . ¿Este refactor cambia algo?


¿Es mejor inicializar String o dejarlo como nulo?

Su premisa es errónea: no inicializar la cadena no significa que su valor sea nulo.

No se le permite usar una variable local antes de que se le haya asignado, para evitar que use accidentalmente un valor que no pretendía. Como tal, el valor no es "nulo", es indefinido (*).

Esto se llama verificación de asignación definitiva y está ahí para evitar ciertos tipos de errores. Si le da a la variable un valor que no necesita darle, deshabilita esta verificación y, por lo tanto, está abierto a los errores de los que el compilador estaba tratando de protegerlo.

Por ejemplo, si el código se ve así:

private String myMethod(String gender) { String newString = ""; if(gender.equals("a")) newString = internal.getValue(); else if (gender.equals("b"); newString = external.getValue(); // Oops! meant to check if gender.equals("c") return newString; }

es posible que tenga un error, porque falta un caso que no haya verificado.

Si hubiera asignado explícitamente null a la variable, tendría el mismo problema; pero ahora su método devolvería nulo, y posiblemente causaría un NPE en el código de llamada.

Si hubiera omitido el = "" , el compilador dejaría de usar newString en la devolución.

(Asignar y reasignar la variable también significa que la variable no sería efectivamente final, por lo que no podría usarla dentro de una clase lambda o anónima).

(*) Esto solo se aplica a variables locales y miembros final / variables estáticas. Los miembros de la clase no tienen que ser asignados definitivamente antes de su uso si no son definitivos, lo cual es una costura rica para errores y una buena razón para hacer que los miembros de la clase sean definitivos siempre que sea posible. Y, técnicamente, los miembros final se inicializan primero al valor predeterminado de su tipo, por lo que puede leerlos como null antes de que se inicialicen.


En su caso (si es otra condición) no hay necesidad de inicializar el String , simplemente puede ponerlo como String newString; y eso estaría bien porque de cualquier manera, al final tendrá un valor diferente.

private String myMethod(String gender) { String newString; if(gender.equals("a")) newString = internal.getValue(); else newString = external.getValue(); // Missing return statement. }

Además, veo que tiene una función que devuelve una cadena. Suponiendo que la variable newString es lo que va a devolver, en lugar de crear una variable de cadena, simplemente puede devolver la cadena en la condición:

private String myMethod(String gender) { if(gender.equals("a")) return internal.getValue(); else return external.getValue(); }


Es mejor inicializar solo una String (o cualquier otra cosa) si hay un escenario en el que se usa el valor inicial.

En su caso, ha asignado newString a un literal de cadena que no tiene otro propósito que confundir al lector.

Debería ser evidente que el rendimiento y la funcionalidad no cambiarán de manera relevante.


Mi opinión sobre la forma más corta sin el operador terniario (que creo que disminuye la legibilidad):

private String myMethod(String gender) { if(gender.equals("a")) return internal.getValue(); return external.getValue(); }

Probablemente tendría una construcción completa if {...} else {...} como las otras respuestas en mi propio código.

Además, no todos los depuradores pueden mostrar fácilmente lo que se devuelve de un método como parte del flujo normal, por lo que puede ser más fácil si el valor de retorno se captura en una variable y ENTONCES se devuelve (donde el punto de interrupción se puede poner en la declaración de retorno)


Mis universidades tienen razón, esto se puede hacer con el operador de tenary. Además, creo que es muy importante evitar NullPoiterExeptions con la mayor frecuencia posible. ¿Qué pasaría si el género fuera nulo? NullPointerException Cambiaría "a" y género como este:

private String myMethod(String gender) { return "a".equals(gender) ? internal.getValue() : external.getValue(); }


Para responder a la pregunta directa: no es necesario asignar un valor inicialmente aquí; todas las ramas de la ejecución del código newString un valor a newString . Por lo tanto, no necesita inicializarlo en absoluto. De lo contrario, inicializaría a lo que desee como valor "predeterminado".

En lugar de dos retornos o una declaración de ramificación para asignar una variable, simplemente regresaría con un ternario:

private String myMethod(String gender) { return gender.equals("a") ? internal.getValue() : external.getValue(); }


Puede hacer que esta cadena sea final y mantenerse sin asignar para asegurarse de que todas las ramas if asignan el valor:

final String result; if (condition1) { result = "one"; } else if (condition2) { result = "two"; } else { result = "other"; } return result;

Con este enfoque, el compilador verificará que la variable de result se haya asignado una vez en cada rama. Puede ser útil si agrega una rama de condición más, o si intenta sobrescribir la variable por error: el compilador fallará y mostrará el error.


Según el documento de Java :

Valores predeterminados

No siempre es necesario asignar un valor cuando se declara un campo. El compilador establecerá los campos declarados pero no inicializados en un valor predeterminado razonable. En términos generales, este valor predeterminado será cero o nulo, según el tipo de datos. Sin embargo, confiar en estos valores predeterminados generalmente se considera un mal estilo de programación.

Las variables locales son ligeramente diferentes; el compilador nunca asigna un valor predeterminado a una variable local no inicializada. Si no puede inicializar su variable local donde se declara, asegúrese de asignarle un valor antes de intentar usarla. Acceder a una variable local no inicializada dará como resultado un error en tiempo de compilación.