Co to są „znaki łączące” w identyfikatorach Java?


208

Czytam SCJP i mam pytanie dotyczące tej linii:

Identyfikatory muszą zaczynać się od litery, znaku waluty ($) lub znaku łączącego, takiego jak znak podkreślenia (_). Identyfikatory nie mogą zaczynać się cyfrą!

Stwierdza, że ​​poprawna nazwa identyfikatora może zaczynać się od łączącego znaku, takiego jak znak podkreślenia. Myślałem, że podkreślenia to jedyna ważna opcja? Jakie są inne łączące się postacie ?


2
Jeśli chodzi o „znak waluty”: odwiedzający to pytanie w Wielkiej Brytanii mogą być zaskoczeni i zainteresowani, wiedząc, że zgodnie z możliwością rozpoczęcia od znaku waluty „a”, identyfikatory Java mogą, zgodnie z prawem, zaczynać się symbolem funta (£).
8bitjunkie

11
Pamiętaj, że od wersji Java 8 _jest to „przestarzały” identyfikator. W szczególności kompilator emituje następujące ostrzeżenie: (użycie „_” jako identyfikatora może nie być obsługiwane w wersjach późniejszych niż Java SE 8) .
aioobe

4
@aioobe Yup. Brian Goetz mówi, że „odzyskują” _do wykorzystania w przyszłych funkcjach językowych . Identyfikatory zaczynające się od znaku podkreślenia są nadal w porządku, ale pojedynczy znak podkreślenia jest błędem, jeśli jest używany jako nazwa parametru lambda i ostrzeżenie wszędzie indziej.
Boann

1
W przypadku kodu bajtowego wszystko, co po sekwencji nie zawiera, . ; [ / < > :to: stackoverflow.com/questions/26791204/… docs.oracle.com/javase/specs/jvms/se7/html/… Wszystko inne jest ograniczeniem tylko do języka Java.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

@Boann Zabawne jest to, że nie zezwalają na jego użycie w lambdas, ale prawdopodobnie wróci jako identyfikator „zignoruj ​​ten argument”, który zostanie użyty np. W lambdas. Ja tylko starałem się go używać tak: _, _ -> doSomething();.
user31389,

Odpowiedzi:


268

Oto lista łączących się postaci. Są to znaki używane do łączenia słów.

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

To kompiluje się w Javie 7.

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

Przykład. W tym przypadku tpjest to nazwa kolumny i wartość dla danego wiersza.

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

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

Następujące

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

odciski

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


109
Nie mogę się doczekać dnia, kiedy odziedziczę kod używający tych identyfikatorów!
Marko Topolnik,

58
@MarkoTopolnik Uważaj, czego sobie życzysz. ;)
Peter Lawrey

3
BTW Możesz także użyć dowolnego z symboli walut. int ৲, ¤, ₪₪₪₪;: D
Peter Lawrey,

17
Mógłbym wrzucić jeden lub dwa z nich do mojego kodu, tylko dla kopnięć! I sprawdzenie, czy system kompilacji jest rzeczywiście zgodny z UTF-8.
Marko Topolnik,

82
Jak o @GrahamBorland if( ⁀ ‿ ⁀ == ⁀ ⁔ ⁀) lub if ($ == $)lub if (¢ + ¢== ₡)lubif (B + ︳!= ฿)
Peter Lawrey

25

iteruj przez wszystkie 65 000 znaków i pytaj Character.isJavaIdentifierStart(c). Odpowiedź brzmi: „podjąć” dziesiętnie 8255


14
Nie mogłem się oprzeć (w Scali): (1 to 65535).map(_.toChar).filter(Character.isJavaIdentifierStart).size- daje 48529 znaków ...
Tomasz Nurkiewicz

wydaje się, że jest kilka postaci w okolicach 65 tys., 12 tys. i 8,5 tys. itd.
Markus Mikkolainen,

nie ustępuje, jeśli powiesz „! isLetter” i „! isDigit”
Markus Mikkolainen

2546 + 2547 przynajmniej „rysunek pudełka ...”
Markus Mikkolainen,

3
Łączna liczba = 90648, ale zamierzam Character.MAX_CODE_POINT, co prawdopodobnie jest więcej niż 2<<16.
Martijn Courteaux,

7

Ostateczną specyfikację legalnego identyfikatora Java można znaleźć w specyfikacji języka Java .


3
Nie jestem pewien, czy faktycznie w pełni odpowiada (dorozumiane) pytanie, które znaki mogą uruchomić identyfikator Java. Po linkach kończymy na Character.isJavaIdentifierStart (), który stwierdza, że znak może uruchomić identyfikator Java, jeśli tylko jeden z następujących warunków jest spełniony: ... ch jest symbolem waluty ( takim jak „$”); ch jest łączącym znakiem interpunkcyjnym ( takim jak „_”).
CVn

1
Wygląda na to, że specyfikacja pozostawia ostateczną listę dopuszczalnych znaków do implementacji, więc może potencjalnie być inna dla wszystkich.
Greg Hewgill

3
@GregHewgill To byłoby głupie, biorąc pod uwagę, jak ściśle określone jest wszystko inne. Myślę, że są to rzeczywiste klasy znaków Unicode, które są zdefiniowane (gdzie indziej?) W standardzie Unicode. isJavaIdentifierStart () wspomina getType (), a symbol waluty i interpunkcja łącznika są również typami, które mogą być zwracane przez tę funkcję, więc listy mogą być tam podane. „Kategoria ogólna” jest w rzeczywistości specyficznym terminem w standardzie Unicode. Więc byłoby prawidłowe wartości L[wszystko] Nl, Sc, Pc.
Random832

3
@GregHewgill jest poprawny. Specyfikacja jest krótka i przejrzysta i jest zdefiniowana przez Character.isJavaIdentifierStart () i Character.isJavaIdentifierPart (). Koniec. Kluczową rzeczą do zapamiętania jest to, że Unicode ewoluuje; nie wpadnij w pułapkę myślenia o zestawach znaków jako ukończonych (łacina jest okropnym przykładem; zignoruj ​​ją). Znaki są tworzone przez cały czas. Zapytaj swoich japońskich przyjaciół. Spodziewaj się, że prawne identyfikatory Java zmieniają się z czasem - i jest to celowe. Chodzi o to, aby pozwolić ludziom pisać kod w ludzkich językach. Prowadzi to do trudnego wymogu umożliwienia zmiany.
James Moore,

6

Oto lista znaków łącznika w standardzie Unicode. Nie znajdziesz ich na klawiaturze.

U + 005F LOW LINE _
U + 203F UNDERTIE ‿
U + 2040 CHARACTER TIE ⁀
U + 2054 INVERTED UNDERTIE ⁔
U + FE33 FORMULARZ
PREZENTACJI DLA PIONOWEJ NISKIEJ LINII ︳ U + FE34 FORMULARZ PREZENTACJI DLA PIONOWEJ FALISTEJ NISKIEJ LINII ︴
U + FE4D DED ﹍
U + FE4E CENTRELINE LOW LINE ﹎
U + FE4F WAVY LOW LINE ﹏
U + FF3F FULLWIDTH LOW LINE _


5
Nie wiem, jakiego układu klawiatury używasz, ale z pewnością mogę dość łatwo wpisać _ (U + 005F) :)
bdonlan

4

Znak łączący służy do łączenia dwóch znaków.

W Javie łączącym znakiem jest ten, dla którego Character.getType (int codePoint) / Character.getType (char ch) zwraca wartość równą Character.CONNECTOR_PUNCTUATION .

Zauważ, że w Javie informacje o znakach są oparte na standardzie Unicode, który identyfikuje łączące się znaki, przypisując im ogólną kategorię Pc, która jest aliasem dla Connector_Punctuation .

Poniższy fragment kodu,

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

wypisuje znaki łączące, których można użyć do uruchomienia identyfikatora na 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

Następujące kompilacje na jdk1.6.0_45,

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

Najwyraźniej powyższa deklaracja nie kompiluje się na jdk1.7.0_80 i jdk1.8.0_51 dla następujących dwóch łączących się znaków (kompatybilność wsteczna ... ups !!!),

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

W każdym razie, pomijając szczegóły, egzamin koncentruje się tylko na podstawowym zestawie znaków łacińskich .

Ponadto w przypadku legalnych identyfikatorów w Javie specyfikacja znajduje się tutaj . Użyj interfejsów API klasy znaków, aby uzyskać więcej informacji.


1

Jednym z najbardziej, no i fajnych znaków dozwolonych w identyfikatorach Java (jednak nie na początku) jest znak Unicode o nazwie „Zero Width Non Joiner” (& zwnj ;, U + 200C, https://en.wikipedia.org / wiki / Zero-width_non-joiner ).

Miałem to raz w kodzie XML wewnątrz wartości atrybutu zawierającej odwołanie do innej części tego kodu XML. Ponieważ ZWNJ ma „zerową szerokość”, nie można go zobaczyć (z wyjątkiem, gdy idzie się razem z kursorem, jest wcześniej wyświetlany bezpośrednio na znaku). Nie można go również zobaczyć w pliku dziennika i / lub danych wyjściowych konsoli. Ale tak było przez cały czas: kopiuj i wklej w polach wyszukiwania, ale nie znalazłem wskazanej pozycji. Wpisanie (widocznej części) ciągu w polu wyszukiwania znalazło jednak określone położenie. Zajęło mi to trochę czasu, aby to rozgryźć.

Wpisanie Zero-Width-Non-Joiner jest w rzeczywistości dość łatwe (zbyt łatwe), gdy używasz europejskiego układu klawiatury, przynajmniej w jego niemieckim wariancie, np. „Europatastatur 2.02” - można go uzyskać za pomocą AltGr + „.”, Dwóch klawiszy, które niestety znajdują się bezpośrednio obok siebie na większości klawiatur i można je łatwo przypadkowo połączyć.

Powrót do Java: Pomyślałem, że możesz napisać taki kod:

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

z drugim i dołączonym przez łącznika o zerowej szerokości (nie mogę tego zrobić w powyższym kodzie wyciętym w edytorze stackoverflow), ale to nie działało. IntelliJ (16.3.3) nie narzekał, ale JavaC (Java 8) narzekał na już zdefiniowany identyfikator - wygląda na to, że JavaC faktycznie zezwala na znak ZWNJ jako część identyfikatora, ale przy użyciu refleksji, aby zobaczyć, co robi, ZWNJ znak zostaje usunięty z identyfikatora - coś, czym nie są znaki takie jak ‿.


0

Lista znaków, których możesz użyć w swoich identyfikatorach (a nie tylko na początku), jest znacznie przyjemniejsza:

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

Lista jest następująca:

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

Obejmuje większość znaków kontrolnych! Mam na myśli dzwony i gówno! Możesz ustawić swój kod źródłowy na dzwonek fn! Lub użyj znaków, które będą wyświetlane tylko czasami, takich jak miękki łącznik.


Zawiera znak DEL. :-(
Todd O'Bryan
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.