Quais são os prós e os contras de ter um tipo CaseInsensitiveString em Java? [fechadas]

8

Estou tentado a criar um final class CaseInsensitiveString implements CharSequence.

Isso nos permitiria definir variáveis ​​e campos desse tipo, em vez de usar um regular String. Também podemos ter, por exemplo Map<CaseInsensitiveString, ?>, a Set<CaseInsensitiveString>, a , etc.

Quais são alguns dos prós e contras dessa abordagem?

poligenelubricants
fonte
Potenciais preocupações: espaço, necessidade de internar, desempenho, cobrança de lixo, etc.
polygenelubricants

Respostas:

26

A distinção entre maiúsculas e minúsculas é uma propriedade da comparação, não do objeto (*). Você deseja comparar a mesma sequência independentemente do caso ou não, dependendo do contexto.

(E você tem todo um tipo de worms, pois a comparação que não diferencia maiúsculas de minúsculas depende do idioma - i é maiúscula como İ em turco - e até do contexto - dependendo da palavra e do dialeto ß podem ser maiúsculas como SS ou SZ em alemão.)

(*) Pode ser uma propriedade do objeto que contém a string, mas isso é um pouco diferente de ser uma propriedade da própria string. E você pode ter uma classe que não tem estado, exceto uma sequência, e a comparação de duas instâncias dessa classe usará uma comparação que não diferencia maiúsculas de minúsculas. Mas essa classe não será uma cadeia de uso geral, pois não fornecerá métodos esperados para uma cadeia de uso geral e fornecerá métodos que não são. Essa classe não será chamada CaseInsensitiveString, mas PascalIdentifier ou o que for pertinente para descrevê-la. E, BTW, o algoritmo de comparação independente de maiúsculas e minúsculas provavelmente será fornecido por seu objetivo e independente de localidade.

AProgrammer
fonte
1
Então, você recomendaria TreeSet<String>usar String.CASE_INSENSITIVE_ORDERsobre a HashSet<CaseInsensitiveString>? Observe que usar TreeSetmeios O(log n)para contains. Além disso, esta comparação é inconsistente com equals, o que significa que a resultante TreeSetnão obedece à geral Setcontrato (ou seja, pode contains(x), mesmo que não tem nenhum elemento que é equalsa x).
polygenelubricants
Desde meados dos anos 90, as tabelas de hash genéricas que eu projetei usam tanto uma função de hash quanto uma função de igualdade como parâmetros genéricos, com um padrão deduzido do tipo de chave. (Se não for o caso dos fornecidos pela biblioteca Java, arriscarei a explicação de que eles foram projetados por alguém mais familiarizado com a programação OO do que a programação genérica. Digitar fortemente o tipo com essas operações é algo que você precisa fazer no POO, mas um cheiro de código no GP).
APJRrammer
@AProgrammer As coleções Java usam a equals()implementação em cada objeto. Há uma implementação padrão, que qualquer objeto pode substituir. Eu não acho que você possa definir o hash, mas nunca tentei - as tabelas sempre funcionavam bem sem se preocupar com isso (uma razão pela qual gosto de Java em C ++ :)).
Michael K
1
@ AProgrammer - Não concordo com "Insensibilidade ao caso é uma propriedade da comparação, não do objeto" e com a condição "talvez o objeto, mas não a string". Isso pode descrever como estão as coisas, mas a questão é sobre uma mudança proposta na forma como as coisas são. No módulo 3 aritmético, 2 é uma abreviação de {..., -4, -1, 2, 5, 8, 11, ...}. A notação representa uma abstração, mas não é a mesma coisa que a abstração. Por que 'H' não pode representar a abstração {'h', 'H'}? Os caracteres não existem na memória do computador - se um código representa 'H' ou {'h', 'H'}, é uma abstração.
Steve314
1
@ AProgrammer - no segundo parágrafo, eu provavelmente concordo. No mínimo, isso implicaria cadeias inglesas que não diferenciam maiúsculas de minúsculas, cordas turcas que não diferenciam maiúsculas de minúsculas etc. Uma classe com subclasses ou uma opção i18n, IOW. E então você obtém o problema de despacho duplo (como comparar duas seqüências que não diferenciam maiúsculas de minúsculas e opções de idioma diferentes). Eu acho que está de volta à "propriedade da comparação". Droga!
Steve314
7

Apenas fora do topo da minha cabeça:

Prós:

  • Faz com que muitos documentos se auto-documentem, por exemplo:
    • bool UserIsRegistered(CaseInsensitiveString Username)
  • Pode simplificar as comparações
  • Pode remover o potencial de erros de comparação

Contras:

  • Pode ser uma perda de tempo
    • as pessoas podem simplesmente converter cadeias regulares em minúsculas se precisarem de comparações que não diferenciam maiúsculas de minúsculas
  • Usá-lo para código front-end causará problemas de capitalização
    • Por exemplo, se você costuma CaseInsensitiveStringarmazenar um nome de usuário, mesmo que faça sentido fazer comparações de back-end que não diferenciam maiúsculas de minúsculas, o código do front-end exibirá o nome do usuário como "bob smith" ou "BOB SMITH"
  • Se sua base de código já usa seqüências regulares, você terá que voltar e alterá-las ou viver com inconsistência
Maxpm
fonte
4
Dependendo da implementação, seu segundo ponto "Contras" não precisa ser válido - você pode implementar CaseInsensitiveString para armazenar com distinção entre maiúsculas e minúsculas e simplesmente substituir os operadores de comparação.
tdammers
1
@ tdammers: se o CaseInsensitiveString é armazenado com case e, em seguida, com o operador de comparação substituído, isso reforça o ponto do @AProgrammer de que o operador de comparação poderia ter sido dissociado do objeto de string que seja.
rwong
3
@ Tdammers - algumas coisas já funcionam da mesma forma. Os sistemas de arquivos do Windows preservam maiúsculas e minúsculas, por exemplo, mas não fazem distinção entre maiúsculas e minúsculas para comparações. Não é um sistema ruim, mas pode causar confusão quando você deseja "renomear" algo para mudar o caso. Basicamente, às vezes você ainda precisa de comparação com distinção entre maiúsculas e minúsculas para evitar fazer julgamentos ruins sobre se uma renomeação está fazendo uma mudança genuína - e se há um caso especial, talvez haja outros também.
Steve314
@rwong: eu concordo. O melhor seria comparações explícitas que não diferenciam maiúsculas de minúsculas, quando necessário. No entanto, às vezes você deseja que as strings se comportem como strings SQL (com um agrupamento de IC) e, em seguida, preservar maiúsculas e minúsculas no armazenamento, mas ignorar maiúsculas e minúsculas na comparação seria a correspondência mais próxima.
Tdammers
4

CaseInsensitiveString não é uma má idéia, depende do seu uso, desde que você não espere que ele funcione junto com String.

Você pode converter um CaseInsensitiveString em uma String ou vice-versa, e é tudo o que você deve fazer.

Problema acontecerá se você tentar fazer algo como

class CaseInsensitiveString {
  private String value;

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

Você está fadado ao fracasso se tornar sua CaseInsensitiveString corporativa com uma String normal, porque estará violando a simetria e a transitividade por equals () (e outros contratos)

No entanto, pergunte a si mesmo: em qual caso você realmente precisa deste CaseInsensitiveString que não é adequado para usar String.CASE_INSENSITIVE_ORDER? Aposto que não muitos. Tenho certeza de que vale a pena ter essa aula especial, mas pergunte a si mesmo primeiro.

Adrian Shum
fonte
2

Criar tipos explicitamente no seu domínio / modelo é uma prática muito boa. Como Maxpm disse, é auto-documentável. Também uma grande vantagem: as pessoas não podem (por acidente) usar informações erradas. A única coisa negativa que isso teria seria que assustaria os programadores juniores (e até alguns médios).

Ivo Limmen
fonte
1

Uma classe CaseInsensitiveString e seus auxiliares adicionam muito código e tornam tudo menos legível que o 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)) ...

é mais complexo, menos documentado e menos flexível do que

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

As implementações usadas com mais freqüência na Web fazem distinção entre maiúsculas e minúsculas - XML, JavaScript. Em termos de desempenho, é sempre melhor usar a função / propriedade / objeto mais apropriada para cada caso.

Se você estiver lidando com estruturas - XML ​​ou JS ou similar, a distinção entre maiúsculas e minúsculas é importante. É muito mais rápido usando bibliotecas do sistema.

Se você estiver lidando com dados em um banco de dados, conforme mencionado acima, a indexação do banco de dados deve ser usada para cadeias que fazem distinção entre maiúsculas e minúsculas.

Se você estiver manipulando dados em tempo real, é importante fazer o cálculo do custo de conversão necessário para cada sequência. É provável que as seqüências de caracteres sejam comparadas ou classificadas de alguma forma.

Alper TÖR
fonte