¿Por qué Java String no tiene métodos estáticos de manipulación de cadenas?

17

¿Por qué los diseñadores de Java no crearon versiones estáticas de métodos de manipulación de cadenas en la java.lang.Stringclase? A los que me refiero son los siguientes métodos, pero la pregunta también puede extenderse a otros métodos no estáticos en la clase.

concat(String)                        substring(int, int)
replace(char, char)                   toLowerCase()
replace(CharSequence, CharSequence)   toLowerCase(Locale)
replaceAll(String, String)            toString()
replaceFirst(String, String)          toUpperCase()
split(String)                         toUpperCase(Locale)
split(String, int)                    trim()
substring(int)

Tener solo versiones no estáticas de estos métodos obliga a la comprobación nula explícita en cualquier lugar al que deba llamarse dicho método. Por ejemplo, simplemente llamar example = example.trim()conduciría a NullPointerException si String example = null. Por lo tanto, el programador tiene que hacer la siguiente comprobación nula repetitiva:

if (example != null)
    example = example.trim();
// OR:
example = (example==null) ? null : example.trim();
example = (example==null) ? null : example.substring(5);

Me imagino que habría sido mucho más conveniente si Stringhubiera versiones estáticas de estos métodos (quizás incluso exclusivamente ), que tomarían la cadena de entrada como primer argumento:

example = String.trim(example);
example = String.replace(example, 'a', 'b');
example = String.substring(example, 5);

Esto habría llevado a un código más limpio escrito por programadores que se habría ocupado automáticamente de los casos nulos simplemente devolviendo nulo, en lugar de obligar a los programadores a manejar explícitamente los casos nulos. La devolución de nulo tiene sentido para mí, ya que manipular una cadena nula debería dar como resultado una cadena nula , no un error.

¿Por qué los diseñadores de Java no pensaron en esto cuando diseñaron la Stringclase en Java 1 o Java 2, o incluso agregaron esa funcionalidad en una versión posterior de Java?

ADTC
fuente
17
Sugeriría reemplazar "¿Por qué los diseñadores de Java no pensaron en X" por "¿Por qué los diseñadores de Java decidieron en contra de X"? Dales el crédito básico de no ser ciego a la opción.
Avner Shahar-Kashtan
55
nulles un estado excepcional y debe manejarse explícitamente.
CodesInChaos
2
@ KonradMorawski: Personalmente, encuentro que es un mal uso grosero de los métodos de extensión. Si tiene un valor nulo, entonces, ¿qué está haciendo tratando de invocar métodos? Simplemente confundirá a todos los que lean ese código. Es una pobre reimplementación de un Maybe<T>tipo, supongo.
Phoshi
1
@Phoshi hay que tener en cuenta que los métodos de extensión NO son métodos reales, solo son sintaxis de azúcar. Pero estoy de acuerdo en que es controvertido. Desearía que C # / Java ofreciera algún tipo de seguridad nula sintáctica incorporada, como, por ejemplo, Kotlin. string name = employee?.personalData?.name. Solo como un atajo para todos estos if (employee != null)s repetitivos . Pregunta SO relacionada: stackoverflow.com/questions/1196031/…
Konrad Morawski
2
@ADTC Erm, te das cuenta de que un programa no puede predecir de antemano que un valor es nulo, ¿verdad? - Debe definir los contratos entre sus interfaces de manera que pueda estar seguro de si un valor puede ser nulo o no. La comprobación nula en todas partes significa que tiene un problema de diseño del programa.
Uooo

Respuestas:

30

La devolución de nulo tiene sentido para mí, ya que manipular una cadena nula debería dar como resultado una cadena nula, no un error

Bueno, esa es tu opinión. Otros pueden argumentar que las operaciones de cadena en un objeto nulo, que no contiene una cadena, no tienen sentido y, por lo tanto, deberían arrojar una excepción

Por qué los "diseñadores de Java" hicieron o no hicieron algo es difícil de responder.

Ya hay bibliotecas por ahí que pueden realizar operaciones de cadena nulas, por ejemplo, StringUtils de Apache Commons. Puede usar eso o bibliotecas similares si las necesita.


Adición basada en tus comentarios

Al leer los comentarios, parece que el verdadero problema que enfrenta es que debe verificar nulltodo el código. Eso puede ser un indicador de un mal diseño del programa sin contratos claramente definidos entre las interfaces. Es posible que desee leer Evitar "! = Null" declaraciones en Java?

Uooo
fuente
1
Gracias por sus comentarios. Supongo que la verdadera pregunta es, ¿por qué tenemos que depender de una biblioteca externa o clases caseras cuando una característica tan básica puede formar parte de Java estándar?
ADTC
44
@ADTC planteemos la pregunta al revés: ¿por qué los "diseñadores de Java" deberían incluir algo en el lenguaje, si ya hay muchas bibliotecas buenas, bien probadas y documentadas? Cómo definir una "característica básica" se basa en la opinión. ¿La mayoría de los proyectos no necesitan alguna biblioteca externa para la "funcionalidad básica" (pruebas unitarias, burlas, fecha y hora, ...)? No es gran cosa, ¿verdad?
Uooo
Una forma de lidiar con los nulos es usar Guava's Optional- code.google.com/p/guava-libraries/wiki/…
Konrad Morawski
10

En mi opinión, todo el enfoque "si arg es nulo devuelve nulo" a los métodos de escritura aumenta innecesariamente la complejidad ciclomática de su programa.

Las primeras bibliotecas de Java usaban el enfoque de retorno nulo, pero los chicos de JDK siempre se protegían contra nulo con excepciones.

Con el tiempo, creo que este último enfoque ha resultado ser el claro ganador.

¿Por qué? Dado que los campos nulos rompen muchos principios oo. Simplemente no puede tratarlos como miembros de una clase polimórfica. Esto significa que siempre debe codificar casos especiales para nulo y, por lo tanto, su complejidad ciclomática se dispara cuando tiene que suponer que las cosas pueden ser nulas.

Para resolver sus problemas, considere usar el patrón de objeto nulo en lugar de confiar en campos nulos.

Alexander Torstling
fuente
2
Pero Stringno es polimórfico, ¿no? ¿Y cómo utiliza el patrón de objeto nulo para un tipo ya existente como String?
svick
La cadena no es polimórfica, no. Pero aun así, le gustaría saber que puede llamar a métodos de instancia en cualquier referencia de cadena que tenga. Esto funciona para todas las referencias no nulas. La cadena ya tiene un objeto nulo: la cadena vacía. Al igual que las listas tienen la lista vacía. Entonces pregúntese por qué la cadena vacía no es suficiente en su caso. Supongo que usas una cadena nula para marcar algún caso especial. Pregúntese si puede usar una bandera separada para ese caso especial.
Alexander Torstling
@AlexanderTorstling: un campo de tipo intpredeterminado es cero en lugar de null. Conceptualmente, debería ser posible tener un stringtipo cuyo valor predeterminado sería una cadena vacía en lugar de null[dicho tipo podría ser semánticamente para Stringlo que intes Integer]. El hecho de que un no vacío stringcontenga internamente una referencia a un objeto de montón sería un detalle de implementación; no hay razón para que no pueda comportarse semánticamente como un primitivo.
supercat
@supercat: De acuerdo. Creo que hubiera sido mejor prohibir los valores nulos para las referencias a menos que esté explícitamente habilitado. Campos predeterminados no nulos y finales. Muchos tipos ya tienen objetos de comportamiento nulo
Alexander Torstling el
@AlexanderTorstling: tener ubicaciones de almacenamiento de todos los tipos predeterminadas a todos los bytes cero, y proporcionar que los tipos de estructura se puedan asignar a través de la copia de todos los bytes, simplifica enormemente un marco, pero implica que los tipos con semántica de referencia mutable deben predeterminarse a nulo. Sin embargo, hubiera sido útil contar con un soporte de marco para los tipos de valor que encapsularían una sola referencia y se "encajonarían" como, y podrían desempaquetar, de ese tipo de referencia .
supercat
3

No digo que esta sea la razón, pero a excepción de toString, todos estos métodos se encapsulan fácilmente en una clase auxiliar estática, mientras que lo contrario no es cierto.

Es decir, si desea Stings.toUpper (entrada de cadena), el código para eso es fácil de escribir, pero si desea instance.toUpper y todo lo que tiene es String.toUpper, bueno, eso es imposible ... a menos que introduzcan métodos de extensión, que probablemente ni siquiera se consideró en ese momento.

jmoreno
fuente
Buen punto, aunque es más un comentario que una respuesta. Pero incluso teniendo en cuenta eso, ¿por qué tenemos que depender de una biblioteca externa o clases caseras cuando una característica tan básica puede formar parte de Java estándar?
ADTC
2
A partir de ahora, tiene String.format(estático), pero no puede hacerlo "something %s".format(id).
Konrad Morawski
@adtc: porque no es una característica básica del lenguaje hacerlo a través de una clase estática. A partir de esa premisa, hay muchas razones para no hacerlo: código innecesario / aumento de código, funcionalidad duplicada, costo de desarrollo / mantenimiento.
jmoreno
-2

En java, esa cadena es un objeto. Esa es una elección de diseño.

Las referencias a objetos pueden ser nulas y son nulas si no hay ningún objeto asignado. Si llama a dicho objeto, se produce una NullPointerException. Ese es el comportamiento estándar.

Los diseñadores de Java eligieron tener cadenas como objeto y que esos métodos arrojen excepciones de puntero nulo es lo que obtienes si quieres que las cadenas sean objetos.

¿Por qué los diseñadores de Java no pensaron en esto cuando diseñaron la clase String en Java 1 o Java 2, o incluso agregaron esa funcionalidad en una versión posterior de Java?

Probablemente lo pensaron y decidieron incorporar el comportamiento oo.

Pieter B
fuente
¿Puedo saber cómo se crean métodos estáticos para ocuparse de casos nulos y no de comportamiento OO ? Para ser claros, no digo que lo sea, pero estoy tratando de entender por qué dices que la decisión de diseño es incorporar el comportamiento OO.
ADTC
Los métodos estáticos son más como funciones. Y para el uso que desee, ni siquiera deberían ser parte de la clase de cadena, sino parte de alguna clase de utilidad. Al igual que las funciones de clase de matemáticas.
Pieter B
44
El hecho de que las cadenas sean objetos no significa que la clase String no pueda tener métodos estáticos. Y de hecho ya tiene algunos, por ejemplo. String.format. (Lo mismo en C #, por cierto). Entonces, si esa es una opción de diseño, no puede provenir únicamente del hecho de que las cadenas son objetos, y no se aplica de manera consistente.
Konrad Morawski
@PieterB No me quejaría si al menos tales métodos se proporcionaran en una Stringsclase de utilidad, como si tuviéramos una Arraysclase de utilidad ( aunque entiendo que se creó por pura necesidad debido a que las matrices son una especie de cruce extraño entre primitivas y objetos: ) ) ... siempre que fuera parte de Java estándar y no requiriera dependencias.
ADTC