Kwestie zestawów znaków są same w sobie mylące i skomplikowane, ale ponadto należy pamiętać dokładne nazwy zestawów znaków. Czy to "utf8"
jest Czy "utf-8"
? A może "UTF-8"
? Podczas wyszukiwania przykładów kodu w Internecie zobaczysz wszystkie powyższe. Dlaczego nie nadać im nazw stałych i używać Charset.UTF8
?
java
character-encoding
serg
źródło
źródło
MessageDigest#getInstance()
mówiąc, ta sama historia trwa .Odpowiedzi:
Prosta odpowiedź na zadane pytanie jest taka, że dostępne ciągi znaków zestawu znaków różnią się w zależności od platformy.
Jednak istnieje sześć, które muszą być obecne, więc dla tych dawnych można było stworzyć stałe. Nie wiem, czemu nie byli.
JDK 1.4 zrobił świetną rzecz, wprowadzając typ Charset. W tym momencie nie chcieliby już podawać stałych String, ponieważ celem jest, aby wszyscy używali instancji Charset. Dlaczego więc nie podać sześciu standardowych stałych Charseta? Zapytałem Martina Buchholza, ponieważ akurat siedział obok mnie, i powiedział, że nie ma naprawdę szczególnie dobrego powodu, z wyjątkiem tego, że w tamtym czasie wszystko było nadal w połowie upieczone - zbyt mało API JDK zostało zmodernizowanych do zaakceptuj Charset, a spośród nich przeciążenia Charset zwykle działały nieco gorzej.
To smutne, że dopiero w JDK 1.6 w końcu skończyli wyposażać wszystko w przeciążenia Charset. I że ta sytuacja dotycząca wydajności wstecznej nadal istnieje (powód, dla którego jest niesamowicie dziwny i nie mogę tego wyjaśnić, ale jest związany z bezpieczeństwem!).
Krótko mówiąc - po prostu zdefiniuj własne stałe lub skorzystaj z klasy Charsets Guava, z którą łączył się Tony Pony (choć ta biblioteka nie jest jeszcze tak naprawdę wydana).
Aktualizacja:
StandardCharsets
klasa jest w JDK 7.źródło
String(byte bytes[], int offset, int length, Charset charset)
implementacji. W rzeczywistości uderzenie wydajności wcale nie jest trywialne przy tworzeniu małego ciągu z dużego bajtu [].Dwa lata później StandardCharset Java 7 definiuje teraz stałe dla 6 standardowych zestawów znaków.
Jeśli utkniesz na Javie 5/6, możesz użyć stałych znaków Guava , jak sugerują Kevin Bourrillion i Jon Skeet.
źródło
Twierdziłbym, że możemy zrobić znacznie więcej niż to ... dlaczego gwarantowane dostępność zestawów znaków nie jest dostępne bezpośrednio?
Charset.UTF8
powinno być odniesieniem doCharset
, a nie nazwą jako ciągiem znaków. W ten sposób nie musielibyśmy radzić sobie wUnsupportedEncodingException
każdym miejscu.Pamiętaj, myślę również, że .NET wybrał lepszą strategię, domyślnie wszędzie używając UTF-8. Następnie spieprzył, nazywając po prostu właściwość kodowania „domyślny system operacyjny”
Encoding.Default
- co nie jest wartością domyślną w samym .NET :(Wróć do rantingu na temat obsługi zestawu znaków Java - dlaczego nie ma konstruktora dla
FileWriter
/FileReader
który bierzeCharset
? Zasadniczo są to prawie bezużyteczne klasy z powodu tego ograniczenia - prawie zawsze potrzebujeszInputStreamReader
okołoFileInputStream
lub odpowiednika dla danych wyjściowych :(Pielęgniarka, pielęgniarka - gdzie jest moje lekarstwo?
EDYCJA: Przyszło mi do głowy, że tak naprawdę nie odpowiedziałem na pytanie. Prawdziwą odpowiedzią jest prawdopodobnie „nikt nie pomyślał o tym” lub „ktoś zaangażowany uważał, że to zły pomysł”. Zdecydowanie sugerowałbym, aby wewnętrzne klasy narzędziowe zawierające nazwy lub zestawy znaków unikały powielania wokół bazy kodu ... Albo możesz po prostu użyć tej, której używaliśmy w Google, kiedy ta odpowiedź była napisana po raz pierwszy . (Należy pamiętać, że od wersji Java 7 wystarczy użyć
StandardCharsets
zamiast tego).źródło
W Javie 1.7
import java.nio.charset.StandardCharsets
dawny:
StandardCharsets.UTF_8
StandardCharsets.US_ASCII
źródło
Obecny stan API kodowania pozostawia wiele do życzenia. Niektóre części Java 6 API nie akceptują
Charset
zamiast łańcucha (wlogging
,dom.ls
,PrintStream
, nie mogą być inne). Nie pomaga to, że kodowania mają różne nazwy kanoniczne dla różnych części standardowej biblioteki.Rozumiem, jak rzeczy dotarł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 tutaj .
W przypadku UTF-8 wartości kanoniczne są
"UTF-8"
dlajava.nio
i"UTF8"
dlajava.lang
ijava.io
. Jedyne kodowania, których specyfikacja wymaga środowiska JRE, to: US-ASCII; ISO-8859-1; UTF-8; UTF-16BE; UTF-16LE; UTF-16 .źródło
Dawno temu zdefiniowałem klasę użyteczności ze stałymi zestawami 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 )
anew String( byte[], String charset_name )
i odkrył, że ta ostatnia realizacja jest ZNACZNIE szybciej. Jeśli spojrzysz pod maską na kod źródłowy, zobaczysz, że rzeczywiście podążają zupełnie inną ścieżką.Z tego powodu dołączyłem narzędzie do tej samej klasy
Dlaczego konstruktor String (bajt [], Charset) nie robi tego samego, bije mnie.
źródło
Charset
trzeba rejestrować, więc może się zdarzyć wyjątek. IIRC, wprowadzono pewne zmiany w JDK7, aby przyspieszyć dla znanych dobrychCharset
implementacji (wyeliminować dodatkową kopię).