Después de una discusión con algunos de mis colegas, tengo una pregunta 'filosófica' sobre cómo tratar el tipo de datos char en Java, siguiendo las mejores prácticas.
Supongamos un escenario simple (obviamente, este es solo un ejemplo muy simple para dar un significado práctico a mi pregunta) donde, dada una 's' de cadena como entrada, debe contar la cantidad de caracteres numéricos presentes en ella.
Estas son las 2 posibles soluciones:
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++;
}
}
¿Cuál de los dos es más "limpio" y cumple con las mejores prácticas de Java?
VK_
constantes que se supone que debes usar; en segundo lugar, usar códigos char es mejor que char Java es un lenguaje de tipo seguro que no debes hacer una verificación de tipos cruzados. @Brandin Se llama prácticas de codificaciónVK_*
constantes corresponden a claves, no a caracteres .Respuestas:
Ambos son horribles, pero el primero es más horrible.
Ambos ignoran la capacidad incorporada de Java para decidir qué caracteres son "numéricos" (a través de métodos en
Character
). Pero el primero no solo ignora la naturaleza Unicode de las cadenas, suponiendo que solo puede haber 0123456789, sino que también oculta incluso este razonamiento no válido al usar códigos de caracteres que tienen sentido solo si conoce algo sobre el historial de codificaciones de caracteres.fuente
matches("[0-9]+")
, en lugar de explotar el truco de rango históricamente motivado.Ninguno. Deje que la clase de caracteres incorporada de Java lo descubra por usted.
Hay unos pocos rangos de caracteres más que los dígitos ASCII que cuentan como dígitos, y ninguno de los ejemplos que publicó los contará. El JavaDoc para
Character.isDigit()
listas de estos rangos de caracteres como siendo dígitos válidos:Dicho esto, uno debería delegar
Character.isDigit()
incluso con esta lista. A medida que se llenen nuevos planos Unicode, se actualizará el código Java. Actualizar la JVM podría hacer que el código antiguo funcione con nuevos caracteres de dígitos sin problemas. También es SECO : al localizar el código "es un dígito" en un lugar al que se hace referencia en otro lugar, se pueden evitar los aspectos negativos de la duplicación de código (es decir, errores). Finalmente, observe la última línea: esta lista no es exhaustiva y hay otros dígitos.Personalmente, preferiría delegar en las bibliotecas principales de Java y dedicar mi tiempo a tareas más productivas que "calcular qué es un dígito".
La única excepción a esta regla es si realmente necesita probar los dígitos ASCII literales y no otros dígitos. Por ejemplo, si está analizando una secuencia y solo los dígitos ASCII (a diferencia de otros dígitos) tienen un significado especial, entonces no sería apropiado usarlos
Character.isDigit()
.En ese caso, escribiría otro método, por ejemplo,
MyClass.isAsciiDigit()
y pondría la lógica allí. Obtiene los mismos beneficios de la reutilización de código, el nombre es muy claro en cuanto a lo que está comprobando y la lógica es correcta.fuente
Si alguna vez escribe una aplicación en C que usa EBCDIC como el conjunto de caracteres básico y necesita procesar caracteres ASCII, use
48
y57
. Estas haciendo eso? No lo creo.Sobre el uso
isDigit()
: depende. ¿Estás escribiendo un analizador JSON? Solo0
para9
ser aceptados como dígitos, así que no useisDigit()
, verifique>= '0'
y<= '9'
. ¿Estás procesando la entrada del usuario? ÚseloisDigit()
siempre que el resto del código pueda manejar la cadena y convertirla en un número correctamente.fuente
El segundo ejemplo es claramente superior. El significado del segundo ejemplo es inmediatamente obvio cuando miras el código. El significado del primer ejemplo solo es obvio si ha memorizado toda la tabla ASCII en su cabeza.
Debe distinguir entre verificar un carácter específico o verificar un rango o clase de caracteres.
1) Verificación de un personaje específico.
Para los caracteres ordinarios, utilice el carácter literal, por ejemplo,
if(ch=='z')...
. Si comprueba caracteres especiales como tabulación o salto de línea, debe usar los escapes, comoif (ch=='\n')...
. Si el carácter que está buscando es inusual (por ejemplo, no se reconoce inmediatamente o no está disponible en un teclado estándar), puede usar un código de caracteres hexadecimales en lugar del carácter literal. Pero como un código hexadecimal es un "valor mágico", lo extraería a una constante y lo documentaría:Los códigos hexadecimales son la forma estándar de especificar códigos de caracteres.
2) Verificación de una clase o rango de personajes
Realmente no debería estar haciendo esto directamente en el código de la aplicación, sino que debería encapsularlo en una clase separada solo relacionada con la clasificación de caracteres. Y debe variar esto, ya que las bibliotecas ya existen para este propósito, y la clasificación de caracteres suele ser más compleja de lo que piensa, al menos si considera caracteres fuera del rango ASCII.
Si solo le preocupan los caracteres en el rango ASCII, podría usar literales de caracteres en esta biblioteca, de lo contrario probablemente usaría literales hexadecimales. Si observa el código fuente de la biblioteca de caracteres incorporada de Java, también se refiere a valores de caracteres y rangos utilizando hexadecimal, ya que así es como se especifican en el estándar Unicode.
fuente
'\x2603'
para ser explícito que está probando el valor de un carácter con una codificación hexadecimal y no cualquier número aleatorio.Siempre es mejor usarlo
c >= '0'
porquec >= 48
necesitas convertir c en código ascii.fuente
Las expresiones regulares ( RegEx s) tienen una clase de caracteres específica para los dígitos
\d
, que puede usarse para eliminar cualquier otro carácter de su cadena. La longitud de la cadena resultante es el valor deseado.Sin embargo, tenga en cuenta que los RegEx son computacionalmente más exigentes que las otras soluciones propuestas, por lo tanto, no deberían preferirse en general .
fuente