Que sont les «caractères de connexion» dans les identificateurs Java?

208

Je lis pour SCJP et j'ai une question concernant cette ligne:

Les identificateurs doivent commencer par une lettre, un caractère monétaire ($) ou un caractère de connexion tel que le trait de soulignement (_). Les identifiants ne peuvent pas commencer par un chiffre!

Il indique qu'un nom d'identifiant valide peut commencer par un caractère de connexion tel que le trait de soulignement. Je pensais que les soulignés étaient la seule option valable? Quels sont les autres personnages connectés ?

Lucky Luke
la source
2
Concernant "un caractère monétaire": les visiteurs britanniques à cette question peuvent être surpris et intéressés de savoir que, tout en étant en mesure de commencer par "un" caractère monétaire, les identificateurs Java peuvent, légalement, commencer par le symbole de la livre sterling (£).
8bitjunkie
11
Notez que depuis Java 8, _est un identifiant "obsolète". Plus précisément, le compilateur émet l'avertissement suivant: (l'utilisation de '_' comme identifiant peut ne pas être prise en charge dans les versions après Java SE 8) .
aioobe
4
@aioobe Yup. Brian Goetz dit qu'ils "récupèrent" _pour être utilisés dans les futures fonctionnalités linguistiques . Les identificateurs qui commencent par un trait de soulignement sont toujours corrects, mais un seul trait de soulignement est une erreur s'il est utilisé comme nom de paramètre lambda et un avertissement partout ailleurs.
Boann
1
Pour le bytecode, tout ce qui par séquence ne contient pas . ; [ / < > :va: stackoverflow.com/questions/26791204/… docs.oracle.com/javase/specs/jvms/se7/html/… Tout le reste est une restriction Java uniquement.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
@Boann Le plus drôle, c'est qu'ils interdisent son utilisation dans les lambdas, mais il reviendra probablement comme identifiant "ignorer cet argument", qui sera utilisé par exemple dans les lambdas. Je viens d' essayer de l' utiliser comme ceci: _, _ -> doSomething();.
user31389

Réponses:

268

Voici une liste de personnages qui se connectent. Ce sont des caractères utilisés pour connecter des mots.

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

Cela se compile sur Java 7.

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

Un exemple. Dans ce cas, tpc'est le nom d'une colonne et la valeur d'une ligne donnée.

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

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

Le suivant

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

impressions

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

Peter Lawrey
la source
109
J'attends avec impatience le jour où j'hériterai du code qui utilise ces identifiants!
Marko Topolnik
58
@MarkoTopolnik Faites attention à ce que vous souhaitez. ;)
Peter Lawrey
3
BTW Vous pouvez également utiliser n'importe lequel des symboles monétaires. int ৲, ¤, ₪₪₪₪;: D
Peter Lawrey
17
Je pourrais en jeter un ou deux dans mon code, juste pour les coups de pied! Et pour tester si le système de build est vraiment compatible UTF-8.
Marko Topolnik
82
@GrahamBorland Que diriez-vous if( ⁀ ‿ ⁀ == ⁀ ⁔ ⁀) ou if ($ == $)ou if (¢ + ¢== ₡)ouif (B + ︳!= ฿)
Peter Lawrey
25

parcourir tous les caractères 65k et demander Character.isJavaIdentifierStart(c). La réponse est: "Undertie" décimal 8255

Markus Mikkolainen
la source
14
Je n'ai pas pu résister (à Scala): (1 to 65535).map(_.toChar).filter(Character.isJavaIdentifierStart).size- donne 48529 caractères ...
Tomasz Nurkiewicz
il semble y avoir quelques personnages près de 65k et 12k et 8.5k etc.
Markus Mikkolainen
ne cède pas si vous dites "! isLetter" et "! isDigit"
Markus Mikkolainen
2546 + 2547 au moins "dessin de boîte ..."
Markus Mikkolainen
3
Nombre total = 90648, mais je vais le faire Character.MAX_CODE_POINT, ce qui est probablement plus que 2<<16.
Martijn Courteaux
7

La spécification définitive d'un identifiant Java légal peut être trouvée dans la spécification du langage Java .

Greg Hewgill
la source
3
Je ne suis pas sûr que cela réponde pleinement à la question (implicite) de quels caractères peuvent commencer un identificateur Java. Les liens suivants nous aboutissent à Character.isJavaIdentifierStart () qui indique qu'un caractère peut démarrer un identificateur Java si et seulement si l'une des conditions suivantes est remplie: ... ch est un symbole monétaire ( tel que "$"); ch est un caractère de ponctuation de connexion ( tel que "_").
un CVn
1
Il semble que la spécification laisse la liste finale des caractères acceptables à l'implémentation, elle pourrait donc être différente pour tout le monde.
Greg Hewgill
3
@GregHewgill Ce serait stupide, compte tenu de la précision de tout le reste. Je pense que ce sont de véritables classes de caractères Unicode, qui sont définies (où ailleurs?) Dans la norme Unicode. isJavaIdentifierStart () mentionne getType (), et le symbole monétaire et la ponctuation du connecteur sont également des types qui peuvent être renvoyés par cette fonction, de sorte que les listes peuvent y être fournies. "Catégorie générale" est en fait un terme spécifique dans la norme Unicode. Ainsi , les valeurs valides seraient L[tous], Nl, Sc, Pc.
Random832
3
@GregHewgill est correct. La spécification est courte et claire, et elle est définie par Character.isJavaIdentifierStart () et Character.isJavaIdentifierPart (). La fin. L'essentiel à retenir est qu'Unicode évolue; ne tombez pas dans le piège de penser que les jeux de caractères sont terminés (le latin est un exemple terrible; ignorez-le). Les personnages sont créés tout le temps. Demandez à vos amis japonais. Attendez-vous à ce que les identificateurs java légaux changent au fil du temps - et c'est intentionnel. Le but est de laisser les gens écrire du code dans les langages humains. Cela conduit à une exigence difficile pour permettre le changement.
James Moore
6

Voici une liste de caractères de connecteur en Unicode. Vous ne les trouverez pas sur votre clavier.

U + 005F LIGNE INFÉRIEURE _
U + 203F SOUS-TÊTE ‿
U + 2040 CRAVATE DE CARACTÈRE ⁀
U + 2054 SOUS-TÊTE INVERSÉE ⁔
U + FE33 FORMULAIRE DE
PRÉSENTATION POUR LA LIGNE LÉGÈRE VERTICALE ︳ U + FE34 FORMULAIRE DE PRÉSENTATION POUR LA LIGNE LÉGÈRE INFÉRIEURE VERTICALE ︴
U + FE4D LIGNE BASSE ÉCRASÉE ﹍
U + FE4E CENTRELINE LOW LINE ﹎
U + FE4F WAVY LOW LINE ﹏
U + FF3F PLEINE LARGEUR LOW LOW _

Simulant
la source
5
Je ne sais pas quelle disposition de clavier vous utilisez, mais je peux certainement taper _ (U + 005F) assez facilement :)
bdonlan
4

Un caractère de connexion est utilisé pour connecter deux caractères.

En Java, un caractère de connexion est celui pour lequel Character.getType (int codePoint) / Character.getType (char ch) renvoie une valeur égale à Character.CONNECTOR_PUNCTUATION .

Notez qu'en Java, les informations sur les caractères sont basées sur la norme Unicode qui identifie les caractères de connexion en leur affectant la catégorie générale Pc, qui est un alias pour Connector_Punctuation .

L'extrait de code suivant,

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 les caractères de connexion qui peuvent être utilisés pour démarrer un identificateur sur 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

Ce qui suit se compile sur jdk1.6.0_45,

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

Apparemment, la déclaration ci-dessus ne parvient pas à se compiler sur jdk1.7.0_80 et jdk1.8.0_51 pour les deux caractères de connexion suivants (compatibilité descendante ... oups !!!),

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

Quoi qu'il en soit, les détails mis à part, l'examen se concentre uniquement sur le jeu de caractères latin de base .

De plus, pour les identifiants légaux en Java, la spécification est fournie ici . Utilisez les API de classe de caractères pour obtenir plus de détails.

sxnamit
la source
1

L'un des caractères les plus amusants autorisés dans les identificateurs Java (mais pas au début) est le caractère unicode nommé "Zero Width Non Joiner" (& zwnj ;, U + 200C, https://en.wikipedia.org / wiki / Zero-width_non-joiner ).

J'ai eu ceci une fois dans un morceau de XML à l'intérieur d'une valeur d'attribut contenant une référence à un autre morceau de ce XML. Étant donné que le ZWNJ est de «largeur nulle», il ne peut pas être vu (sauf en marchant avec le curseur, il est affiché directement sur le caractère précédent). Il ne pouvait pas non plus être vu dans le fichier journal et / ou la sortie de la console. Mais il était là tout le temps: le copier-coller dans les champs de recherche l'a obtenu et n'a donc pas trouvé la position référencée. La saisie de la partie (visible de la) chaîne dans le champ de recherche a cependant trouvé la position référencée. Cela m'a pris un certain temps pour comprendre cela.

Taper un Zero-Width-Non-Joiner est en fait assez facile (trop facile) lorsque vous utilisez la disposition du clavier européen, au moins dans sa variante allemande, par exemple "Europatastatur 2.02" - il est accessible avec AltGr + ".", Deux touches qui Malheureusement, ils sont situés directement les uns à côté des autres sur la plupart des claviers et peuvent facilement être joints accidentellement.

Retour à Java: j'ai bien pensé, vous pouvez écrire du code comme celui-ci:

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

avec le second i ajouté par un non-joiner de largeur nulle (ne peut pas faire cela dans le code ci-dessus coupé dans l'éditeur de stackoverflow), mais cela n'a pas fonctionné. IntelliJ (16.3.3) ne s'est pas plaint, mais JavaC (Java 8) s'est plaint d'un identificateur déjà défini - il semble que JavaC autorise en fait le caractère ZWNJ dans le cadre d'un identificateur, mais lors de l'utilisation de la réflexion pour voir ce qu'il fait, le ZWNJ le caractère est supprimé de l'identifiant - ce que les caractères comme ‿ ne sont pas.

Ulrich Grepel
la source
0

La liste des caractères que vous pouvez utiliser dans vos identifiants (plutôt que juste au début) est beaucoup plus amusante:

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 liste est:

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

Il comprend la plupart des personnages de contrôle! Je veux dire des cloches et de la merde! Vous pouvez faire sonner votre code source la cloche fn! Ou utilisez des caractères qui ne s'affichent que parfois, comme le trait d'union doux.

Aleksandr Dubinsky
la source
Il comprend \ u007f, le caractère DEL. :-(
Todd O'Bryan