¿Qué son los "caracteres de conexión" en los identificadores de Java?

208

Estoy leyendo para SCJP y tengo una pregunta con respecto a esta línea:

Los identificadores deben comenzar con una letra, un carácter de moneda ($) o un carácter de conexión como el guión bajo (_). ¡Los identificadores no pueden comenzar con un número!

Establece que un nombre de identificador válido puede comenzar con un carácter de conexión como el guión bajo. ¿Pensé que los subrayados eran la única opción válida? ¿Qué otros personajes de conexión hay?

LuckyLuke
fuente
2
Con respecto a "un carácter de moneda": los visitantes del Reino Unido a esta pregunta pueden estar sorprendidos e interesados ​​en saber que, de acuerdo con la posibilidad de comenzar con un "carácter de moneda", los identificadores de Java pueden, legalmente, comenzar con el símbolo de libra (£).
8bitjunkie
11
Tenga en cuenta que desde Java 8, _es un identificador "obsoleto". Específicamente, el compilador emite la siguiente advertencia: (el uso de '_' como identificador podría no ser compatible en versiones posteriores a Java SE 8) .
aioobe
44
@aioobe Sí. Brian Goetz dice que están "reclamando" _para su uso en futuras funciones del lenguaje . Los identificadores que comienzan con un guión bajo todavía están bien, pero un solo guión bajo es un error si se usa como un nombre de parámetro lambda y una advertencia en cualquier otro lugar.
Boann
1
Para el código de bytes , cualquier cosa por secuencia que no contenga . ; [ / < > :va: stackoverflow.com/questions/26791204/… docs.oracle.com/javase/specs/jvms/se7/html/… Todo lo demás es una restricción solo de Java.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
@Boann Lo curioso es que no permiten su uso en lambdas, pero probablemente volverá como un identificador de "ignorar este argumento", que se usará, por ejemplo, en lambdas. Sólo traté de utilizar de esta manera: _, _ -> doSomething();.
user31389

Respuestas:

268

Aquí hay una lista de personajes de conexión. Estos son caracteres utilizados para conectar palabras.

http://www.fileformat.info/info/unicode/category/Pc/list.htm

U+005F _ LOW LINE
U+203F  UNDERTIE
U+2040  CHARACTER TIE
U+2054  INVERTED UNDERTIE
U+FE33  PRESENTATION FORM FOR VERTICAL LOW LINE
U+FE34  PRESENTATION FORM FOR VERTICAL WAVY LOW LINE
U+FE4D  DASHED LOW LINE
U+FE4E  CENTRELINE LOW LINE
U+FE4F  WAVY LOW LINE
U+FF3F _ FULLWIDTH LOW LINE

Esto compila en Java 7.

int _, ‿, ⁀, ⁔, ︳, ︴, ﹍, ﹎, ﹏, _;

Un ejemplo. En este caso tpes el nombre de una columna y el valor de una fila dada.

Column<Double> tp = table.getColumn("tp", double.class);

double tp = row.getDouble(︴tp︴);

El seguimiento

for (int i = Character.MIN_CODE_POINT; i <= Character.MAX_CODE_POINT; i++)
    if (Character.isJavaIdentifierStart(i) && !Character.isAlphabetic(i))
        System.out.print((char) i + " ");
}

huellas dactilares

$ _ ¢ £ ¤ ¥ ؋ ৲ ৳ ৻ ૱ ௹ ฿ ៛ ‿ ⁀ ⁔ ₠ ₡ ₢ ₣ ₤ ₥ ₦ ₧ ₨ ₩ ₪ ₫ € ₭ ₮ ₯ ₰ ₱ ₲ ₳ ₴ ₵ ₶ ₷ ₸ ₹ ꠸ ﷼ ︳ ︴ ﹍ ﹎ ﹏ ﹩ $ _ ¢ £ ¥ ₩

Peter Lawrey
fuente
109
¡Espero con ansias el día en que herede algún código que use estos identificadores!
Marko Topolnik el
58
@MarkoTopolnik Tenga cuidado con lo que desea. ;)
Peter Lawrey
3
Por cierto, también puede usar cualquiera de los símbolos de moneda. int ৲, ¤, ₪₪₪₪;: D
Peter Lawrey
17
¡Podría lanzar uno o dos de estos en mi código, solo por diversión! Y para probar si el sistema de compilación es realmente compatible con UTF-8.
Marko Topolnik el
82
@GrahamBorland ¿Qué tal if( ⁀ ‿ ⁀ == ⁀ ⁔ ⁀) o if ($ == $)o if (¢ + ¢== ₡)o?if (B + ︳!= ฿)
Peter Lawrey
25

iterar a través de los caracteres completos de 65k y preguntar Character.isJavaIdentifierStart(c). La respuesta es: "undertie" decimal 8255

Markus Mikkolainen
fuente
14
No pude resistir (en Scala): (1 to 65535).map(_.toChar).filter(Character.isJavaIdentifierStart).size- produce 48529 caracteres ...
Tomasz Nurkiewicz
Parece que hay algunos personajes cerca de 65k y 12k y 8.5k etc.
Markus Mikkolainen
no cede si dices "! isLetter" y "! isDigit"
Markus Mikkolainen
2546 + 2547 al menos "dibujo de caja ..."
Markus Mikkolainen
3
Recuento total = 90648, pero voy a hacerlo Character.MAX_CODE_POINT, que probablemente sea más que 2<<16.
Martijn Courteaux
7

La especificación definitiva de un identificador legal de Java se puede encontrar en la Especificación del lenguaje Java .

Greg Hewgill
fuente
3
No estoy seguro de que realmente responda completamente la pregunta (implícita) de qué caracteres pueden iniciar un identificador de Java. Siguiendo los enlaces terminamos en Character.isJavaIdentifierStart () que establece que un personaje puede iniciar un identificador Java si y solo si una de las siguientes condiciones es verdadera: ... ch es un símbolo de moneda ( como "$"); ch es un carácter de puntuación de conexión ( como "_").
un CVn
1
Parece que la especificación deja la lista final de caracteres aceptables hasta la implementación, por lo que podría ser diferente para todos.
Greg Hewgill
3
@GregHewgill Eso sería una tontería, teniendo en cuenta lo bien especificado que está todo lo demás. Creo que estas son clases de caracteres Unicode reales, que están definidas (¿dónde más?) En el estándar Unicode. isJavaIdentifierStart () menciona getType (), y el símbolo de moneda y la puntuación del conector también son tipos que pueden ser devueltos por esa función, por lo que las listas pueden aparecer allí. "Categoría general" es, de hecho, un término específico en el estándar Unicode. Por lo que los valores válidos serían L[todos], Nl, Sc, Pc.
Random832
3
@GregHewgill es correcto. La especificación es corta y clara, y está definida por Character.isJavaIdentifierStart () y Character.isJavaIdentifierPart (). El fin. La clave para recordar es que Unicode está evolucionando; no caigas en la trampa de pensar que los conjuntos de caracteres están terminados (el latín es un ejemplo terrible; ignóralo). Los personajes se crean todo el tiempo. Pregúntale a tus amigos japoneses. Espere que los identificadores legales de Java cambien con el tiempo, y eso es intencional. El punto es dejar que las personas escriban código en idiomas humanos. Eso lleva a un requisito difícil para permitir el cambio.
James Moore
6

Aquí hay una lista de caracteres de conector en Unicode. No los encontrará en su teclado.

U + 005F LÍNEA BAJA _
U + 203F SUBTENSIÓN ‿
U + 2040 CORBATA DE CARÁCTER ⁀
U + 2054 INVERTIDA SUBTENSIÓN ⁔
U + FE33 FORMULARIO DE PRESENTACIÓN PARA LÍNEA BAJA VERTICAL ︳
U + FE34 FORMULARIO DE PRESENTACIÓN PARA LÍNEA BAJA ONDA VERTICAL ︴
U + FE4D LÍNEA BAJA DASHED ﹍
U + FE4E LÍNEA BAJA CENTRELINA ﹎
U + FE4F LÍNEA BAJA ONDULADA ﹏
U + FF3F LÍNEA BAJA DE ANCHO COMPLETO _

Simulante
fuente
55
No sé qué distribución de teclado estás usando, pero ciertamente puedo escribir _ (U + 005F) con bastante facilidad :)
bdonlan
4

Se utiliza un carácter de conexión para conectar dos caracteres.

En Java, un carácter de conexión es aquel para el que Character.getType (int codePoint) / Character.getType (char ch) devuelve un valor igual a Character.CONNECTOR_PUNCTUATION .

Tenga en cuenta que en Java, la información de los caracteres se basa en el estándar Unicode que identifica los caracteres de conexión al asignarles la categoría general Pc, que es un alias para Connector_Punctuation .

El siguiente fragmento de código,

for (int i = Character.MIN_CODE_POINT; i <= Character.MAX_CODE_POINT; i++) {
    if (Character.getType(i) == Character.CONNECTOR_PUNCTUATION
            && Character.isJavaIdentifierStart(i)) {
        System.out.println("character: " + String.valueOf(Character.toChars(i))
                + ", codepoint: " + i + ", hexcode: " + Integer.toHexString(i));
    }
}

imprime los caracteres de conexión que se pueden usar para iniciar un identificador en jdk1.6.0_45

character: _, codepoint: 95, hexcode: 5f
character: ‿, codepoint: 8255, hexcode: 203f
character: ⁀, codepoint: 8256, hexcode: 2040
character: ⁔, codepoint: 8276, hexcode: 2054
character: ・, codepoint: 12539, hexcode: 30fb
character: ︳, codepoint: 65075, hexcode: fe33
character: ︴, codepoint: 65076, hexcode: fe34
character: ﹍, codepoint: 65101, hexcode: fe4d
character: ﹎, codepoint: 65102, hexcode: fe4e
character: ﹏, codepoint: 65103, hexcode: fe4f
character: _, codepoint: 65343, hexcode: ff3f
character: ・, codepoint: 65381, hexcode: ff65

Las siguientes compilaciones en jdk1.6.0_45,

int _, ‿, ⁀, ⁔, ・, ︳, ︴, ﹍, ﹎, ﹏, _,  = 0;

Aparentemente, la declaración anterior no se compila en jdk1.7.0_80 y jdk1.8.0_51 para los siguientes dos caracteres de conexión (compatibilidad con versiones anteriores ... ¡Uy!),

character: ・, codepoint: 12539, hexcode: 30fb
character: ・, codepoint: 65381, hexcode: ff65

De todos modos, aparte de los detalles, el examen se enfoca solo en el conjunto de caracteres latinos básicos .

Además, para los identificadores legales en Java, la especificación se proporciona aquí . Use las API de la clase Character para obtener más detalles.

sxnamit
fuente
1

Uno de los personajes más divertidos que se permite en los identificadores de Java (aunque no al principio) es el carácter unicode llamado "Zero Width Non Joiner" (& zwnj ;, U + 200C, https://en.wikipedia.org / wiki / Zero-width_non-joiner ).

Una vez tuve esto en un fragmento de XML dentro de un valor de atributo que contiene una referencia a otro fragmento de ese XML. Como el ZWNJ es de "ancho cero", no se puede ver (excepto cuando se camina junto con el cursor, se muestra directamente en el carácter anterior). Tampoco se pudo ver en el archivo de registro y / o la salida de la consola. Pero estuvo allí todo el tiempo: copiar y pegar en los campos de búsqueda lo obtuvo y, por lo tanto, no encontró la posición referida. Sin embargo, al escribir la (parte visible de la) cadena en el campo de búsqueda se encontró la posición referida. Me llevó un tiempo resolver esto.

Escribir un Zero-Width-Non-Joiner es realmente bastante fácil (demasiado fácil) cuando se utiliza la distribución del teclado europeo, al menos en su variante alemana, por ejemplo, "Europatastatur 2.02": se puede acceder con AltGr + ".", Dos teclas que desafortunadamente, se encuentran directamente uno al lado del otro en la mayoría de los teclados y pueden golpearse fácilmente juntos accidentalmente.

De vuelta a Java: pensé bien, podrías escribir un código como este:

void foo() {
    int i = 1;
    int i = 2;
}

con el segundo lo agregué con un ancho cero sin unión (no puedo hacer eso en el código anterior recortado en el editor de stackoverflow), pero eso no funcionó. IntelliJ (16.3.3) no se quejó, pero JavaC (Java 8) sí se quejó de un identificador ya definido: parece que JavaC realmente permite que el personaje ZWNJ forme parte de un identificador, pero cuando usa la reflexión para ver qué hace, el ZWNJ el carácter se elimina del identificador, algo que los caracteres como ‿ no son.

Ulrich Grepel
fuente
0

La lista de caracteres que puede usar dentro de sus identificadores (en lugar de solo al principio) es mucho más divertida:

for (int i = Character.MIN_CODE_POINT; i <= Character.MAX_CODE_POINT; i++)
    if (Character.isJavaIdentifierPart(i) && !Character.isAlphabetic(i))
        System.out.print((char) i + " ");

La lista es:

I wanted to post the output, but it's forbidden by the SO spam filter. That's how fun it is!

¡Incluye la mayoría de los personajes de control! Me refiero a campanas y mierda! ¡Puede hacer que su código fuente toque el timbre fn! O utilice caracteres que solo se mostrarán a veces, como el guión suave.

Aleksandr Dubinsky
fuente
Incluye \ u007f, el carácter DEL. :-(
Todd O'Bryan