¿Cuáles son las ventajas y desventajas de tener un tipo CaseInsensitiveString en Java? [cerrado]

8

Estoy tentado a crear un final class CaseInsensitiveString implements CharSequence.

Esto nos permitiría definir variables y campos de este tipo, en lugar de usar un regular String. También podemos tener, por ejemplo Map<CaseInsensitiveString, ?>, a Set<CaseInsensitiveString>, a , etc.

¿Cuáles son algunos de los pros y los contras de este enfoque?

poligenelubricantes
fuente
Posibles preocupaciones: espacio, necesidad de pasantías, desempeño, recolección de basura, etc.
polygenelubricants

Respuestas:

26

La insensibilidad a mayúsculas y minúsculas es una propiedad de la comparación, no del objeto (*). Querrá comparar la misma cadena independientemente del caso o no dependiendo del contexto.

(Y tiene todo un tipo de gusanos, ya que la comparación entre mayúsculas y minúsculas depende del idioma, i está en mayúsculas como İ en turco, e incluso del contexto, dependiendo de la palabra y el dialecto ß puede ser mayúscula como SS o SZ en alemán.)

(*) Puede ser una propiedad del objeto que contiene la cadena, pero eso es algo diferente de ser una propiedad de la cadena en sí. Y puede tener una clase que no tenga estado excepto una cadena, y al comparar dos instancias de esa clase se usará una comparación de la cadena que no distingue entre mayúsculas y minúsculas. Pero esa clase no será una cadena de propósito general, ya que no proporcionará los métodos esperados para las cadenas de propósito general y proporcionará métodos que no lo son. Esta clase no se llamará CaseInsensitiveString sino PascalIdentifier o lo que sea pertinente para describirlo. Y, por cierto, el algoritmo de comparación independiente del caso probablemente será proporcionado por su propósito y será independiente de la configuración regional.

Un programador
fuente
1
Entonces, ¿recomendaría un TreeSet<String>uso String.CASE_INSENSITIVE_ORDERsobre un HashSet<CaseInsensitiveString>? Tenga en cuenta que el uso de TreeSetmedios O(log n)para contains. Por otra parte, este comparador es incompatible con equals, lo que significa que la resultante TreeSetno obedece al general Setcontrato (es decir, puede contains(x), a pesar de que no tiene ningún elemento que es equalsa x).
polygenelubricants
Desde mediados de los 90, las tablas hash genéricas que he diseñado toman una función hash y una función de igualdad como parámetros genéricos con un valor predeterminado deducido del tipo de clave. (Si no es el caso de los proporcionados por la biblioteca Java, me arriesgaré a la explicación de que fueron diseñados por alguien más familiarizado con la programación OO que la programación genérica, escribir fuertemente el tipo con esas operaciones es algo que debe hacer en OOP pero un código de olor en GP).
Programador
@AProgrammer Las colecciones Java utilizan la equals()implementación en cada objeto. Hay una implementación predeterminada, que cualquier objeto puede anular. No creo que pueda definir el hash, pero nunca lo he intentado: las tablas siempre funcionaron bien sin preocuparme por eso (una razón por la que me gusta Java sobre C ++ :)).
Michael K
1
@AProgrammer - No estoy de acuerdo con "La insensibilidad a mayúsculas y minúsculas es una propiedad de la comparación, no del objeto", y con la condición de "tal vez el objeto pero no la cadena". Esto puede describir cómo están las cosas, pero la pregunta es sobre un cambio propuesto a cómo están las cosas. En la aritmética del módulo 3, 2 es la abreviatura de {..., -4, -1, 2, 5, 8, 11, ...}. La notación representa una abstracción, pero no es lo mismo que la abstracción. ¿Por qué 'H' no puede representar la abstracción {'h', 'H'}? Los caracteres no existen en la memoria de las computadoras, ya sea que un código represente 'H' o {'h', 'H'}, es una abstracción.
Steve314
1
@AProgrammer: en el segundo párrafo, probablemente estoy de acuerdo. Como mínimo, implicaría cadenas inglesas que no distinguen entre mayúsculas y minúsculas, cadenas turcas que no distinguen entre mayúsculas y minúsculas, etc. Una clase con subclases o una opción i18n, IOW. Y luego obtienes el problema del doble despacho (cómo comparar dos cadenas que no distinguen entre mayúsculas y minúsculas con diferentes opciones de idioma). Supongo que eso es de nuevo a "propiedad de la comparación". ¡Maldición!
Steve314
7

Justo al lado de la parte superior de mi cabeza:

Pros:

  • Hace que muchos documentos se auto documenten, por ejemplo:
    • bool UserIsRegistered(CaseInsensitiveString Username)
  • Puede agilizar las comparaciones
  • Puede eliminar la posibilidad de errores de comparación

Contras:

  • Podría ser una pérdida de tiempo
    • las personas pueden convertir cadenas regulares a minúsculas si necesitan comparaciones entre mayúsculas y minúsculas
  • Usarlo para código front-end causará problemas de capitalización
    • Por ejemplo, si usa CaseInsensitiveStringpara almacenar un nombre de usuario, aunque tenga sentido tener comparaciones de fondo que no distingan entre mayúsculas y minúsculas, el código de front-end mostrará el nombre del usuario como "bob smith" o "BOB SMITH"
  • Si su base de código ya usa cadenas regulares, tendrá que regresar y cambiarlas o vivir con inconsistencia
Maxpm
fuente
44
Dependiendo de la implementación, su segundo punto "Contras" no tiene que ser válido: puede implementar CaseInsensitiveString para almacenar mayúsculas y minúsculas y simplemente anular los operadores de comparación.
tdammers
1
@tdammers: si CaseInsensitiveString se almacena con case y luego con el operador de comparación anulado, refuerza el punto de @AProgrammer de que el operador de comparación podría haberse desacoplado de cualquier objeto de cadena.
rwong
3
@tdammers: algunas cosas ya funcionan de manera similar. Los sistemas de archivos de Windows conservan mayúsculas y minúsculas, por ejemplo, pero no distinguen entre mayúsculas y minúsculas para las comparaciones. No es un mal sistema, pero puede causar confusión cuando desea "cambiar el nombre" de algo para cambiar el caso. Básicamente, todavía a veces necesita una comparación entre mayúsculas y minúsculas para evitar hacer juicios erróneos sobre si un cambio de nombre está haciendo un cambio genuino, y si hay un caso especial, tal vez haya otros también.
Steve314
@rwong: estoy de acuerdo. Lo mejor sería hacer comparaciones explícitas que no distingan entre mayúsculas y minúsculas cuando sea necesario. Sin embargo, a veces desea que las cadenas se comporten como cadenas SQL (con una intercalación de CI), y luego preservar el caso en el almacenamiento, pero ignorar el caso en la comparación sería la coincidencia más cercana.
tdammers
4

CaseInsensitiveString no es una mala idea, depende de su uso, siempre que no espere que funcione junto con String.

Puede convertir un CaseInsensitiveString en un String, o viceversa, y eso es todo lo que debe hacer.

El problema ocurrirá si intentas hacer algo como

class CaseInsensitiveString {
  private String value;

  public boolean equals(Object o) {
    // .....
    if (o instanceof String) {
      return value.equalsIgnoreCase((String) o);
    }
  }
}

Está condenado al fracaso si va a hacer que su CaseInsensitiveString sea corporativa con String normal, porque violará la simétrica y la transitiva para equals () (y otros contratos)

Sin embargo, pregúntese, ¿en qué caso realmente necesita este CaseInsensitiveString que no es adecuado para usar String.CASE_INSENSITIVE_ORDER? Apuesto a que no hay muchos casos. Estoy seguro de que habrá un caso que vale la pena tener esta clase especial, pero pregúntese primero.

Adrian Shum
fuente
2

Crear explícitamente tipos en su dominio / modelo es una muy buena práctica. Como dijo Maxpm, es autodocumentado. También una gran ventaja: la gente no puede (por accidente) usar una entrada incorrecta. Lo único negativo que tiene es que asustará a los programadores junior (e incluso a algunos medianos).

Ivo Limmen
fuente
1

Una clase CaseInsensitiveString y sus ayudantes agregan mucho código y harán que todo sea menos legible que el método String.toLoweCase ().

CaseInsensitiveString vaName1 = new CaseInsensitiveString('HeLLo');
//... a lot of lines here
CaseInsensitiveString vaName2 = new CaseInsensitiveString('Hello');
//... a lot of lines here
if (varName1.equals(varName2)) ...

es más complejo, menos autodocumentado y menos flexible que

String vaName1 = 'HeLLo';
//... a lot of lines here
String vaName2 = 'Hello';
//... a lot of lines here
if (varName1.toLowerCase().equals(varName2.toLowerCase())) ...
Ando
fuente
0

Las implementaciones más utilizadas en la web distinguen entre mayúsculas y minúsculas: XML, JavaScript. En términos de rendimiento, siempre es mejor usar la función / propiedad / objeto más apropiado para cada caso.

Si se trata de estructuras: XML o JS o similar, la distinción entre mayúsculas y minúsculas es importante. Es mucho más rápido usar bibliotecas del sistema.

Si se trata de datos en una base de datos, como se mencionó anteriormente, la indexación de la base de datos se utilizará para cadenas sensibles a mayúsculas / minúsculas.

Si está manejando datos sobre la marcha, es importante hacer el cálculo del costo de conversión necesario para cada cadena. Es probable que las cadenas se comparen o clasifiquen de alguna manera.

Alper TÖR
fuente