Após uma discussão com alguns colegas, tenho uma pergunta 'filosófica' sobre como tratar o tipo de dados char em Java, seguindo as melhores práticas.
Suponha um cenário simples (obviamente, este é apenas um exemplo muito simples, a fim de dar um significado prático à minha pergunta) , em que, dado um String 's' como entrada, você deve contar o número de caracteres numéricos presentes nele.
Estas são as 2 soluções possíveis:
1)
for(int i=0; i<s.length(); i++) {
if(s.charAt(i) >= 48 && s.charAt(i) <= 57) {
n++;
}
}
2)
for(int i=0; i<s.length(); i++) {
if(s.charAt(i) >= '0' && s.charAt(i) <= '9' ) {
n++;
}
}
Qual dos dois é mais 'limpo' e compatível com as melhores práticas de Java?
VK_
constantes que você deveria usar; em segundo lugar, usar códigos char é melhor que char. Java é uma linguagem de tipo seguro que você não deve fazer verificação de tipo cruzado. @Brandin chamadas práticas de TI da codificaçãoVK_*
constantes correspondem a chaves, não a caracteres .Respostas:
Ambos são horríveis, mas o primeiro é mais horrível.
Ambos ignoram a capacidade interna do Java para decidir quais caracteres são "numéricos" (por meio de métodos
Character
). Mas o primeiro não apenas ignora a natureza Unicode das cadeias, assumindo que pode haver apenas 0123456789, mas também oculta esse raciocínio inválido usando códigos de caracteres que só fazem sentido se você souber algo sobre o histórico das codificações de caracteres.fonte
matches("[0-9]+")
, em vez de explorar o truque de alcance historicamente motivado.Nem. Deixe a classe de caracteres incorporada do Java descobrir por você.
Existem mais intervalos de caracteres do que os dígitos ASCII que contam como dígitos, e nenhum exemplo que você postou os contará. O JavaDoc para
Character.isDigit()
lista esses intervalos de caracteres como sendo dígitos válidos:Dito isto, deve-se delegar para
Character.isDigit()
mesmo com esta lista. À medida que novos planos Unicode são preenchidos, o código Java será atualizado. Atualizar a JVM poderia fazer com que o código antigo funcionasse perfeitamente com novos caracteres de dígito. Também é SECO : localizando o código "é um dígito" em um local referenciado em outro lugar, os aspectos negativos da duplicação de código (ou seja, bugs) podem ser evitados. Por fim, observe a última linha: esta lista não é exaustiva e há outros dígitos.Pessoalmente, prefiro delegar nas principais bibliotecas Java e gastar meu tempo em tarefas mais produtivas do que "descobrir o que é um dígito".
A única exceção a essa regra é se você realmente precisa testar os dígitos ASCII literais e não outros dígitos. Por exemplo, se você estiver analisando um fluxo e apenas dígitos ASCII (em oposição a outros dígitos) tiverem um significado especial, não seria apropriado usá-lo
Character.isDigit()
.Nesse caso, eu escreveria outro método, por exemplo,
MyClass.isAsciiDigit()
e colocaria a lógica lá. Você obtém os mesmos benefícios da reutilização de código, o nome é super claro quanto ao que está verificando e a lógica está correta.fonte
Se você escrever um aplicativo em C que use EBCDIC como o conjunto de caracteres básico e precise processar caracteres ASCII, use
48
e57
. Você está fazendo isso? Acho que não.Sobre o uso
isDigit()
: depende. Você está escrevendo um analisador JSON? Somente0
para9
serem aceitos como dígitos, portanto, não useisDigit()
, verifique>= '0'
e<= '9'
. Você está processando a entrada do usuário? UseisDigit()
enquanto o resto do seu código puder manipular a string e transformá-la em um número corretamente.fonte
O segundo exemplo é claramente superior. O significado do segundo exemplo é imediatamente óbvio quando você olha para o código. O significado do primeiro exemplo é óbvio apenas se você memorizou toda a tabela ASCII em sua cabeça.
Você deve distinguir entre a verificação de um caractere específico ou a verificação de um intervalo ou classe de caracteres.
1) Verificando um caractere específico.
Para caracteres comuns, use o literal literal, por exemplo
if(ch=='z')...
,. Se você verificar caracteres especiais, como tabulação ou quebra de linha, use os escapes, comoif (ch=='\n')...
. Se o caractere que você está procurando é incomum (por exemplo, não é reconhecível imediatamente ou não está disponível em um teclado padrão), você pode usar um código de caractere hexadecimal em vez do caractere literal. Mas como um código hexadecimal é um "valor mágico", você o extrairá para uma constante e o documentará:Os códigos hexadecimais são a maneira padrão de especificar códigos de caracteres.
2) Verificando uma classe ou intervalo de caracteres
Você realmente não deveria fazer isso diretamente no código do aplicativo, mas deveria encapsular em uma classe separada, apenas relacionada à classificação de caracteres. E você deve variar disso, já que as bibliotecas já existem para esse fim, e a classificação de caracteres geralmente é mais complexa do que você pensa, pelo menos se você considerar caracteres fora do intervalo ASCII.
Se você estiver preocupado apenas com caracteres no intervalo ASCII, poderá usar literais de caracteres nesta biblioteca; caso contrário, provavelmente usaria literais hexadecimais. Se você olhar para o código-fonte da biblioteca de caracteres interna Java, ele também se refere a valores e intervalos de caracteres usando hexadecimal, pois é assim que eles são especificados no padrão Unicode.
fonte
'\x2603'
vez disso, para ser explícito que você está testando o valor de um caractere com uma codificação hexadecimal e não apenas qualquer número aleatório.É sempre melhor usar,
c >= '0'
porquec >= 48
você precisa converter c em código ascii.fonte
Expressões regulares ( RegEx ) têm uma classe de caracteres específica para dígitos -
\d
- que podem ser usados para remover qualquer outro caractere da sua string. O comprimento da sequência resultante é o valor desejado.Observe, no entanto, que os RegEx s são computacionalmente mais exigentes que as outras soluções propostas, portanto, não devem ser geralmente preferidos .
fonte