Что такое «соединительные символы» в идентификаторах Java?

208

Я читаю для SCJP, и у меня есть вопрос относительно этой строки:

Идентификаторы должны начинаться с буквы, символа валюты ($) или соединительного символа, такого как подчеркивание (_). Идентификаторы не могут начинаться с цифры!

В нем говорится, что допустимое имя идентификатора может начинаться с соединительного символа, такого как подчеркивание. Я думал, подчеркивания были единственным допустимым вариантом? Какие еще соединительные символы есть?

Счастливчик Люк
источник
2
Относительно "символа валюты": посетители из Великобритании на этот вопрос могут быть удивлены и заинтересованы в том, чтобы в соответствии с возможностью начинать с символа "a", идентификаторы Java по закону могут начинаться с символа фунта (£).
8bitjunkie
11
Обратите внимание, что, начиная с Java 8, _это «устаревший» идентификатор. В частности, компилятор выдает следующее предупреждение: (использование '_' в качестве идентификатора может не поддерживаться в выпусках после Java SE 8) .
aioobe
4
@aioobe Да. Брайан Гетц говорит, что они «возвращаются» _для использования в будущих языковых функциях . Идентификаторы, которые начинаются со знака подчеркивания, все еще в порядке, но одиночное подчеркивание является ошибкой, если используется как имя параметра лямбда-выражения, и предупреждением везде.
Boann
1
Для байткод, ничего по последовательности , которая не содержит . ; [ / < > :идет: stackoverflow.com/questions/26791204/... docs.oracle.com/javase/specs/jvms/se7/html/... Все остальное является Java-единственное ограничение.
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
@Boann Забавно, что они запрещают его использование в лямбдах, но он, вероятно, вернется как идентификатор «игнорировать этот аргумент», который будет использоваться, например, в лямбдах. Я просто пытался использовать его как это: _, _ -> doSomething();.
user31389

Ответы:

268

Вот список соединительных символов. Это символы, используемые для соединения слов.

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

Это компилируется на Java 7.

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

Пример. В данном случае tpэто имя столбца и значение для данной строки.

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

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

Последующий

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

печать

$ _ ¢ £ ¤ ¥ ؋ ৲ ৳ ৻ ૱ ฿ ៛ ⁀ ⁀ ⁔ ₢ ₢ ₣ ₣ ₥ ₥ ₫ ₫ ₫ ₫ ₭ ₮ ₰ ₰ ₵ ₷ ₷ ₸ ꠸ ︴ ﹍ ﹍ ﹩ $ _ ¢ £ ¥ ₩

Питер Лори
источник
109
Я с нетерпением жду того дня, когда я унаследую некоторый код, который использует эти идентификаторы!
Марко Топольник
58
@MarkoTopolnik Будьте осторожны, что вы хотите. ;)
Питер Лоури
3
Кстати, вы можете использовать любой из символов валюты, а также. int ৲, ¤, ₪₪₪₪;: D
Питер Лори
17
Я мог бы бросить один или два из них в свой код, просто для удовольствия! И проверить , является ли система сборки действительно UTF-8 соответствует.
Марко Топольник
82
@GrahamBorland Как насчет if( ⁀ ‿ ⁀ == ⁀ ⁔ ⁀) или if ($ == $)или if (¢ + ¢== ₡)илиif (B + ︳!= ฿)
Питер Лоури
25

переберите все 65 тысяч символов и спросите Character.isJavaIdentifierStart(c). Ответ: "нижнее белье" десятичное 8255

Маркус Микколайнен
источник
14
Я не смог устоять (в Scala): (1 to 65535).map(_.toChar).filter(Character.isJavaIdentifierStart).size- дает 48529 символов ...
Томаш Нуркевич
кажется, что есть несколько символов около 65k и 12k и 8.5k и т. д.
Маркус Микколайнен
не уступает, если вы говорите "! isLetter" и "! isDigit"
Маркус Микколайнен
2546 + 2547 по крайней мере "рисунок коробки ..."
Маркус Микколайнен
3
Общее количество = 90648, но я собираюсь Character.MAX_CODE_POINT, что, вероятно, больше, чем 2<<16.
Мартин Курто
7

Окончательная спецификация допустимого идентификатора Java может быть найдена в Спецификации языка Java .

Грег Хьюгилл
источник
3
Я не уверен, что на самом деле полностью отвечает на (подразумеваемый) вопрос о том, какие символы могут начинать идентификатор Java. Следующие ссылки приводят к Character.isJavaIdentifierStart (), в котором говорится, что символ может начинать идентификатор Java, если и только если выполняется одно из следующих условий: ... ch - символ валюты ( например, "$"); ch - это соединительный знак пунктуации ( например, «_»).
CVN
1
Кажется, что спецификация оставляет окончательный список допустимых символов до реализации, поэтому он может быть разным для всех.
Грег Хьюгилл
3
@GregHewgill Это было бы глупо, учитывая, насколько точно указано все остальное. Я думаю, что это фактические классы символов Unicode, которые определены (где еще?) В стандарте Unicode. isJavaIdentifierStart () упоминает getType (), и символ валюты, и пунктуация коннектора также являются типами, которые могут быть возвращены этой функцией, поэтому списки могут быть указаны там. «Общая категория» фактически является конкретным термином в стандарте Unicode. Таким образом, допустимые значения были бы L[все] Nl, Sc, Pc.
Random832
3
@GregHewgill правильно. Спецификация короткая и понятная, и она определяется Character.isJavaIdentifierStart () и Character.isJavaIdentifierPart (). Конец. Главное, что нужно помнить, это то, что Unicode развивается; не попадайтесь в ловушку мышления наборов символов как законченных (латынь - ужасный пример; игнорируйте ее). Персонажи создаются постоянно. Спросите своих японских друзей. Ожидайте, что законные идентификаторы java изменятся со временем - и это намеренно. Дело в том, чтобы позволить людям писать код на человеческих языках. Это приводит к жестким требованиям для разрешения изменений.
Джеймс Мур
6

Вот список символов соединителя в Unicode. Вы не найдете их на клавиатуре.

U + 005F LOW LINE _
U + 203F UNDERTIE ‿
U + 2040 CHARACTER TIE ⁀
U + 2054 INVERTED UNDERTIE ⁔
U + FE33 ФОРМА ПРЕЗЕНТАЦИИ ДЛЯ ВЕРТИКАЛЬНОЙ НИЗКОЙ ЛИНИИ ︳
U + FE34 ФОРМА ПРЕЗЕНТАЦИИ ДЛЯ ВЕРТИКАЛЬНОЙ ВОЛНОВОЙ НИЗКОЙ ЛИНИИ ︴
U + FE4 ﹍
U + FE4E ЦЕНТРАЛЬНАЯ НИЗКАЯ ЛИНИЯ ﹎
U + FE4F ВОЛНОВАЯ НИЗКАЯ ЛИНИЯ ﹏
U + FF3F ПОЛНАЯ НИЗКАЯ ЛИНИЯ _

симулянт
источник
5
Я не знаю, какую раскладку клавиатуры вы используете, но я, безусловно, могу набрать _ (U + 005F) достаточно легко :)
bdonlan
4

Соединительный символ используется для соединения двух символов.

В Java соединительный символ - это тот, для которого Character.getType (int codePoint) / Character.getType (char ch) возвращает значение, равное Character.CONNECTOR_PUNCTUATION .

Обратите внимание, что в Java информация о символах основана на стандарте Unicode, который идентифицирует соединительные символы, назначая им общую категорию Pc, которая является псевдонимом для Connector_Punctuation. .

Следующий фрагмент кода,

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

печатает соединительные символы, которые можно использовать для запуска идентификатора на 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

Следующие компиляции на jdk1.6.0_45,

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

По-видимому, вышеприведенное объявление не скомпилируется в jdk1.7.0_80 и jdk1.8.0_51 для следующих двух соединительных символов (обратная совместимость ... упс !!!),

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

В любом случае, за исключением деталей, экзамен фокусируется только на наборе символов базовой латиницы .

Кроме того , для юридических identifers в Java, спецификация предоставляется здесь . Используйте API класса Character для получения более подробной информации.

sxnamit
источник
1

Одним из наиболее забавных символов, которые разрешены в идентификаторах Java (но не в начале), является символ Юникода с именем «Zero Width Non Joiner» (& zwnj ;, U + 200C, https://en.wikipedia.org / вики / Zero-width_non-краснодеревщик ).

Я имел это однажды в куске XML внутри значения атрибута, содержащего ссылку на другой кусок этого XML. Поскольку ZWNJ имеет «нулевую ширину», его нельзя увидеть (кроме как при ходьбе с курсором, он отображается прямо на символе раньше). Это также не может быть видно в лог-файле и / или выводе консоли. Но это было все время: скопировать и вставить в поля поиска получили его и, таким образом, не нашли указанную позицию. Набрав (видимую часть) строку в поле поиска, вы найдете указанную позицию. Мне понадобилось время, чтобы понять это.

Ввод Zero-Width-Non-Joiner на самом деле довольно легко (слишком просто) при использовании европейской раскладки клавиатуры, по крайней мере, в ее немецком варианте, например, «Europatastatur 2.02» - это достигается с помощью AltGr + «.», Две клавиши которого к сожалению, на большинстве клавиатур они расположены рядом друг с другом, и их легко можно случайно ударить вместе.

Возвращаясь к Java: я подумал, вы могли бы написать такой код:

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

со вторым я добавил нулевую ширину без соединения (не могу этого сделать в приведенном выше коде, отредактированном в редакторе stackoverflow), но это не сработало. IntelliJ (16.3.3) не жаловался, но JavaC (Java 8) жаловался на уже определенный идентификатор - кажется, JavaC фактически допускает использование символа ZWNJ как части идентификатора, но при использовании отражения, чтобы увидеть, что он делает, ZWNJ символ удаляется из идентификатора - то, что символы, такие как n't, не являются.

Ульрих Грепель
источник
0

Список символов, которые вы можете использовать внутри своих идентификаторов (а не только в начале), гораздо веселее:

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

Список:

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

Включает в себя большинство управляющих символов! Я имею в виду колокола и дерьмо! Вы можете заставить свой исходный код звонить в звонок! Или используйте символы, которые будут отображаться только иногда, например, мягкий дефис.

Александр Дубинский
источник
Он включает в себя символ DEL. :-(
Тодд О'Брайан