2009-11-05 11 views
199

Problemy z zestawem znaków są mylące i skomplikowane, ale oprócz tego należy pamiętać dokładne nazwy swoich zestawów znaków. Czy to jest "utf8"? Lub "utf-8"? A może "UTF-8"? Podczas wyszukiwania w Internecie dla próbek kodu zobaczysz wszystkie powyższe. Dlaczego po prostu nie uczynić ich nazwanymi stałymi i użyć Charset.UTF8?Java: Dlaczego nazwy zestawów znaków nie są stałe?

+18

+1: Zostało to również podsłuch mi cały czas. Ta sama historia dzieje się dla 'MessageDigest # getInstance()' przy okazji. – BalusC

+1

Aby uzyskać prawdziwą odpowiedź, musisz zapytać kogoś w firmie Sun. Powodzenia w tym :-) –

+1

Stephen C. Wierzę, że zostało to omówione na publicznej liście mailingowej. - Ktoś w Słońcu. –

Odpowiedz

152

Prostą odpowiedzią na zadane pytanie jest to, że dostępne ciągi znaków zestawów zależą od platformy.

Jednakże, istnieje sześć, które muszą być obecne, więc stałe mogły być wykonane dla tych, dawno temu. Nie wiem, dlaczego nie byli.

JDK 1.4 zrobił wielką rzecz, wprowadzając typ zestawu słuchawkowego. W tym momencie nie chcieliby już dostarczać stałych String, ponieważ celem jest, aby wszyscy korzystali z instancji Charset. Dlaczego więc nie podać sześciu standardowych stałych Charset? Poprosiłem Martin Buchholz skoro dzieje się siedzący obok mnie i powiedział, że nie było naprawdę szczególnie wielki powód, chyba, że ​​w momencie, rzeczy wciąż połowiczne - zbyt mało JDK API została zmodernizowana do Akceptuj Charset, a tych, które były, przeciążenia Charset zwykle wykonywane nieco gorsze.

To smutne, że to tylko w JDK 1.6, że ostatecznie zakończył wyposażeniowych wszystko z przeciążeniami charset. I że nadal istnieje ta sytuacja wstecz wydajność (powód jest bardzo dziwne i nie potrafię tego wyjaśnić, ale jest związane z bezpieczeństwem!).

Krótko mówiąc - wystarczy zdefiniować własne stałe lub użyj guawy w klasę charsets który Tony Pony powiązany (mimo, że biblioteka nie jest jeszcze naprawdę faktycznie zwolniony).

Aktualizacja: klasa StandardCharsets jest w JDK 7.

+0

Po prostu ciekawy, jaki będzie pomysł, kiedy pojawi się wersja Guava (alfa/beta/cokolwiek)? Strona domowa projektu jest w tym przypadku nieco zawikłana. – Jonik

+0

Żaden indyk dla mnie, dopóki go nie ma! –

+0

* powód, dla którego jest niesamowicie dziwny i nie mogę tego wyjaśnić, ale jest związany z bezpieczeństwem * - możesz utworzyć modyfikowalny ciąg za pomocą niestandardowych zestawów znaków, ale mogłyby one zostać wykonane nawet szybciej niż ciąg (który faktycznie wyszukuje charset). To zaniedbanie/zaniedbanie jak zaimplementowano 'String (bajt bajtów [], int offset, int length, charset charset)'. W rzeczywistości trafienie wydajnościowe wcale nie jest trywialne podczas tworzenia małego ciągu z dużego bajtu []. – bestsss

27

Twierdzę, że możemy zrobić o wiele lepiej ... dlaczego nie mamy zagwarantowanych dostępnych zestawów znaków dostępnych bezpośrednio? Charset.UTF8 powinno być odniesieniem do Charset, a nie nazwą w postaci ciągu. W ten sposób nie musielibyśmy obsługiwać UnsupportedEncodingException w każdym miejscu.

Pamiętajcie, ja też uważam, że .NET wybrał lepszą strategię domyślnie wszędzie na UTF-8. Następnie wkręca się przez nazywanie „domyślny system operacyjny” kodowania własność prostu Encoding.Default - co nie jest domyślny w samym .NET :(

Powrót do ranting o wsparcie charset Java - dlaczego nie jest konstruktorem ? o FileWriter/FileReader który zajmuje Charset Zasadniczo te są niemal bezużyteczne zajęcia z powodu tego ograniczenia - prawie zawsze potrzebować InputStreamReader wokół lub FileInputStream odpowiednik dla wyjścia :(

pielęgniarka, pielęgniarka -

gdzie jest moje lekarstwo?

EDYCJA: Wydaje mi się, że tak naprawdę nie odpowiedział na pytanie. Prawdziwą odpowiedzią jest przypuszczalnie albo "nikt o tym nie pomyślał", albo "ktoś zaangażowany myślał, że to zły pomysł". Zdecydowanie sugeruję, aby wewnętrzne klasy narzędziowe zawierające nazwy lub zestawy znaków unikały duplikowania kodu źródłowego ... Lub można po prostu użyć the one that we use at Google.

+2

+1. Ale jako metoda, a nie pole, aby umożliwić leniwy ładowanie (dobrze, prawdopodobnie będziesz chciał UTF-8, ale istnieje kilka innych zestawów znaków i możesz chcieć podobnych udogodnień dla nich). Niestety wydaje się, że nie jest to zbyt popularne wśród podejmujących decyzje. –

+0

Byłbym zadowolony z metody, aczkolwiek mam nadzieję, że szybkie ładowanie tych bardzo niewielkich zestawów znaków nie będzie znaczącym kosztem. –

+1

Jesteśmy na krucjacie, aby zatrzymać szybkie ładowanie klas./Po prostu przeszukałem JDK dla "UTF-8". Znaleziono 270 wyników w 165 plikach.Chociaż wiele z tego jest w starych śmieciach Apache'a (moim zdaniem jest to zasługa mojego zespołu). –

5

Obecny stan API kodowania pozostawia wiele do życzenia.Niektóre części interfejsu API Java 6 nie akceptują Charset w miejsce ciągu znaków (w logging, dom.ls, PrintStream; mogą istnieć inne). Nie pomaga, aby kodowanie miało różne nazwy kanoniczne dla różnych części standardowej biblioteki.

Rozumiem, jak rzeczy się znalazły tam, gdzie są; nie jestem pewien, czy mam jakieś genialne pomysły, jak je naprawić.


Tak na marginesie ...

Można spojrzeć na nazwy dla Java 6 wdrażania Sun here.

UTF-8, wartości kanoniczne są "UTF-8" do java.nio i "UTF8" do java.lang i java.io. Jedyne kodowania, które specyfikacja wymaga od JRE, to: US-ASCII; ISO-8859-1; UTF-8; UTF-16BE; UTF-16LE; UTF-16.

+2

Nie żartuję z klasy PrintStream, ponieważ klasa wyraźnie mówi: "Klasa PrintWriter powinna być używana w sytuacjach wymagających pisania znaków, a nie bajtów." (Które jest, jak wszystkie sytuacje ...) –

2

Dawno temu zdefiniowałem klasę narzędzi o stałych znaków UTF_8, ISO_8859_1 i US_ASCII.

Również niektóre dawno temu (2+ lat) zrobiłem prosty test wydajności pomiędzy new String(byte[], Charset) i new String(byte[], String charset_name) i odkrył, że ta ostatnia realizacja jest ZNACZNIE szybciej. Jeśli spojrzysz pod maską kodu źródłowego, zobaczysz, że rzeczywiście podążają całkiem inną ścieżką.

Z tego powodu zawierał użyteczność w tej samej klasie

public static String stringFromByteArray (
    final byte[] array, 
    final Charset charset 
) 
{ 
    try 
    { 
     return new String(array, charset.name()) 
    } 
    catch (UnsupportedEncodingException ex) 
    { 
     // cannot happen 
    } 
} 

Dlaczego String (byte [] Kodowanie) konstruktor nie to samo, bije mnie.

+1

'Charset' nie musi być zarejestrowany, więc wyjątek może się zdarzyć .Irc, było kilka zmian w JDK7, aby uczynić go szybszym dla dobrze znanych implementacji' Charset' (wyeliminować dodatkowa kopia). –

99

Dwa lata później i Java 7's StandardCharsets definiuje teraz stałe dla 6 standardowych zestawów znaków.

Jeśli utkniesz na Java 5/6, możesz użyć stałych Guava Charsets, jak sugerują Kevin Bourrillion i Jon Skeet.

26

W Javie 1.7

import java.nio.charset.StandardCharsets

ex: StandardCharsets.UTF_8 StandardCharsets.US_ASCII

Powiązane problemy