O que são "caracteres de conexão" nos identificadores Java?

208

Estou lendo para o SCJP e tenho uma pergunta sobre esta linha:

Os identificadores devem começar com uma letra, um caractere de moeda ($) ou um caractere de conexão, como o sublinhado (_). Os identificadores não podem começar com um número!

Ele afirma que um nome de identificador válido pode começar com um caractere de conexão , como sublinhado. Eu pensei que sublinhados eram a única opção válida? Quais outros caracteres de conexão existem?

LuckyLuke
fonte
2
Em relação a "um caractere de moeda": os visitantes do Reino Unido a esta pergunta podem ficar surpresos e interessados ​​em saber que, de acordo com a possibilidade de começar com um "caractere de moeda", os identificadores Java podem, legalmente, começar com o símbolo de libra (£).
precisa saber é o seguinte
11
Observe que, desde o Java 8, _é um identificador "obsoleto". Especificamente, o compilador emite o seguinte aviso: (o uso de '_' como um identificador pode não ser suportado em releases após o Java SE 8) .
aioobe
4
@aioobe Yup. Brian Goetz diz que eles estão "recuperando" _para uso em recursos de idiomas futuros . Os identificadores que começam com um sublinhado ainda estão ok, mas um único sublinhado é um erro se usado como um nome de parâmetro lambda e um aviso em qualquer outro lugar.
Boann
1
Para o bytecode, qualquer coisa por sequência que não contenha . ; [ / < > :é: stackoverflow.com/questions/26791204/… docs.oracle.com/javase/specs/jvms/se7/html/… Todo o resto é uma restrição apenas para Java.
Ciro Santilli escreveu:
@Boann O engraçado é que eles estão proibindo seu uso em lambdas, mas provavelmente voltará como um identificador "ignore esse argumento", que será usado, por exemplo, em lambdas. Eu apenas tentei usá-lo como este: _, _ -> doSomething();.
precisa saber é o seguinte

Respostas:

268

Aqui está uma lista de caracteres de conexão. Esses são caracteres usados ​​para conectar palavras.

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

Isso compila no Java 7.

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

Um exemplo. Nesse caso, tpé o nome de uma coluna e o valor para uma determinada linha.

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

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

Os seguintes

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 + " ");
}

impressões

$ _ ¢ £ ¤ ¥ ؋ ৲ ৳ ৻ ‿ ⁀ ₠ ₡ ₢ ₣ ₤ ₥ ₧ ₧ ₨ ₪ ₫ ₫ ₫ ₫ ₫ € ₭ ₮ ₱ ₱ ₱ ₱ ₱ ₱ ₱ ₱ ₱ ₱ ₱ ₱ ₱ ₱ ₫ ₫ ₫ ﹩ $ _ ¢ £ ¥ ₩

Peter Lawrey
fonte
109
Estou ansioso pelo dia em que herdo algum código que usa esses identificadores!
Marko Topolnik
58
@MarkoTopolnik Cuidado com o que você deseja. ;)
Peter Lawrey
3
BTW Você também pode usar qualquer um dos símbolos de moeda. int ৲, ¤, ₪₪₪₪;: D
Peter Lawrey
17
Talvez eu jogue uma ou duas delas no meu código, apenas por diversão! E para testar se o sistema de compilação é realmente compatível com UTF-8.
Marko Topolnik
82
@GrahamBorland Que tal if( ⁀ ‿ ⁀ == ⁀ ⁔ ⁀) ou if ($ == $)ou if (¢ + ¢== ₡)ouif (B + ︳!= ฿)
Peter Lawrey 2/12/12
25

itere através dos caracteres de 65k e pergunte Character.isJavaIdentifierStart(c). A resposta é: decimal "undertie" 8255

Markus Mikkolainen
fonte
14
Eu não pude resistir (em Scala): (1 to 65535).map(_.toChar).filter(Character.isJavaIdentifierStart).size- produz 48529 caracteres ...
Tomasz Nurkiewicz 2/12/12
parece haver alguns personagens perto de 65k e 12k e 8.5k etc.
Markus Mikkolainen
rendimento does not se você disser "isLetter!" e "isDigit!"
Markus Mikkolainen
2546 + 2547 pelo menos "desenho da caixa ..."
Markus Mikkolainen
3
Contagem total = 90648, mas eu vou Character.MAX_CODE_POINT, o que provavelmente é mais do que 2<<16.
Martijn Courteaux
7

A especificação definitiva de um identificador Java legal pode ser encontrada em Java Language Specification .

Greg Hewgill
fonte
3
Não tenho certeza de que realmente responda totalmente à pergunta (implícita) de quais caracteres podem iniciar um identificador Java. Os links a seguir terminam em Character.isJavaIdentifierStart (), que declara Um caractere pode iniciar um identificador Java se, e somente se, uma das seguintes condições for verdadeira: ... ch é um símbolo de moeda ( como "$"); ch é um caractere de pontuação de conexão ( como "_").
um CVn
1
Parece que a especificação deixa a lista final de caracteres aceitáveis ​​até a implementação, portanto pode ser diferente para todos.
Greg Hewgill 02/08/2012
3
@GregHewgill Isso seria tolice, considerando o quão bem especificado tudo o resto é. Eu acho que essas são classes de caracteres Unicode reais, que são definidas (onde mais?) No padrão Unicode. isJavaIdentifierStart () menciona getType () e a pontuação da moeda e do símbolo e do conector também são tipos que podem ser retornados por essa função, portanto, as listas podem ser fornecidas lá. "Categoria geral" é de fato um termo específico no padrão Unicode. Assim, os valores válidos seria L[todos], Nl, Sc, Pc.
usar o seguinte código
3
@GregHewgill está correto. A especificação é curta e clara e é definida por Character.isJavaIdentifierStart () e Character.isJavaIdentifierPart (). O fim. O principal a lembrar é que o Unicode está evoluindo; não caia na armadilha de pensar em conjuntos de caracteres como acabados (o latim é um exemplo terrível; ignore-o). Os personagens são criados o tempo todo. Pergunte aos seus amigos japoneses. Espere que os identificadores legais de java mudem ao longo do tempo - e isso é intencional. O objetivo é permitir que as pessoas escrevam código em linguagens humanas. Isso leva a um requisito difícil de permitir mudanças.
James Moore
6

Aqui está uma lista de caracteres do conector em Unicode. Você não os encontrará no teclado.

U + 005F linha baixa _
U + 203F UNDERTIE ‿
U + 2040 PERSONAGEM TIE ⁀
U + 2054 INVERTIDO UNDERTIE ⁔
U + FE33 APRESENTAÇÃO FORMULÁRIO PARA VERTICAL linha baixa _ L
+ FE34 APRESENTAÇÃO FORMULÁRIO PARA VERTICAL WAVY linha baixa ︴
U + FE4D tracejada linha baixa ﹍
LINHA BAIXA CENTRAL
U + FE4E LINE LINHA BAIXA ONDULADA
U + FE4F ﹏ LINHA BAIXA LARGA LARGA U + FF3F _

Simulante
fonte
5
Eu não sei o layout de teclado que você está usando, mas eu certamente pode digitar _ (U + 005F) com bastante facilidade :)
bdonlan
4

Um caractere de conexão é usado para conectar dois caracteres.

Em Java, um caractere de conexão é aquele para o qual Character.getType (int codePoint) / Character.getType (char ch) retorna um valor igual a Character.CONNECTOR_PUNCTUATION .

Observe que em Java, as informações de caracteres são baseadas no padrão Unicode, que identifica os caracteres de conexão, atribuindo a eles a categoria geral Pc, que é um alias para Connector_Punctuation .

O seguinte snippet 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 os caracteres de conexão que podem ser usados ​​para iniciar um identificador no 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

O seguinte compila em jdk1.6.0_45,

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

Aparentemente, a declaração acima falha ao compilar no jdk1.7.0_80 & jdk1.8.0_51 para os dois caracteres de conexão a seguir (compatibilidade com versões anteriores ... oops !!!),

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

Enfim, detalhes à parte, o exame se concentra apenas no conjunto de caracteres latinos básicos .

Além disso, para identificadores legais em Java, a especificação é fornecida aqui . Use as APIs da classe Character para obter mais detalhes.

sxnamit
fonte
1

Um dos caracteres mais divertidos permitidos nos identificadores Java (mas não no início) é o caractere unicode chamado "Zero Width Non Joiner" (& zwnj ;, U + 200C, https://en.wikipedia.org / wiki / Zero-width_non-joiner ).

Eu tive isso uma vez em um pedaço de XML dentro de um valor de atributo, mantendo uma referência a outro pedaço desse XML. Como o ZWNJ tem "largura zero", ele não pode ser visto (exceto ao andar junto com o cursor, ele é exibido logo no caractere anterior). Também não pôde ser visto no arquivo de log e / ou na saída do console. Mas ele estava lá o tempo todo: copiar e colar nos campos de pesquisa conseguiu e, portanto, não encontrou a posição referida. Digitar a parte (visível da cadeia) no campo de pesquisa, no entanto, encontrou a posição referida. Levei um tempo para descobrir isso.

Digitar um não-marceneiro com largura zero é realmente muito fácil (muito fácil) ao usar o layout de teclado europeu, pelo menos em sua variante alemã, por exemplo, "Europatastatur 2.02" - é acessível com AltGr + ".", Duas teclas que infelizmente, estão localizados um ao lado do outro na maioria dos teclados e podem ser facilmente atingidos acidentalmente.

Voltando ao Java: pensei bem, você poderia escrever um código como este:

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

com o segundo anexado por um marceneiro de largura zero (não é possível fazer isso no código acima, capturado no editor do stackoverflow), mas isso não funcionou. O IntelliJ (16.3.3) não reclamou, mas o JavaC (Java 8) reclamou de um identificador já definido - parece que o JavaC realmente permite o caractere ZWNJ como parte de um identificador, mas ao usar a reflexão para ver o que faz, o ZWNJ O caractere é retirado do identificador - algo que caracteres como ‿ não são.

Ulrich Grepel
fonte
0

A lista de caracteres que você pode usar dentro de seus identificadores (e não apenas no início) é muito mais 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 + " ");

A lista é:

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

Inclui a maioria dos caracteres de controle! Quero dizer sinos e merda! Você pode fazer seu código fonte tocar a campainha fn! Ou use caracteres que serão exibidos apenas algumas vezes, como o hífen suave.

Aleksandr Dubinsky
fonte
Inclui \ u007f, o caractere DEL. :-(
Todd O'Bryan