Karakter seti adları neden sabit değildir?


211

Karakter kümesi sorunları kafa karıştırıcı ve karmaşıktır, ancak bunun üzerine karakter kümelerinizin tam adlarını hatırlamanız gerekir. Öyle mi "utf8"? Yoksa "utf-8"? Ya da belki "UTF-8"? İnternette kod örnekleri ararken, yukarıdakilerin tümünü göreceksiniz. Neden onları sadece sabit olarak adlandırmıyorsunuz Charset.UTF8?


19
+1: Bu da beni sürekli rahatsız ediyordu. Bu arada aynı hikaye devam ediyor MessageDigest#getInstance().
BalusC

2
Gerçek cevap için Sun'dan birine sormanız gerekir. İyi şanslar :-)
Stephen C

1
Stephen C: Bunun genel bir posta listesinde tartışıldığına inanıyorum. - Sun'da birileri.
Tom Hawtin - tackline

Yanıtlar:


160

Sorulan sorunun basit cevabı, mevcut karakter dizgilerinin platformdan platforma değiştiğidir.

Bununla birlikte, mevcut olması gereken altı tane var, bu yüzden uzun zaman önce olanlar için sabitler yapılabilirdi. Neden olmadıklarını bilmiyorum.

JDK 1.4, Charset türünü tanıtarak harika bir şey yaptı. Bu noktada, hedef, Charset örneklerini kullanan herkesi elde etmek olduğundan, artık String sabitleri sağlamak istemezlerdi. Öyleyse neden altı standart Charset sabitini vermiyorsunuz? Martin Buchholz'a hemen yanıma oturduğundan beri sordum ve o zamanlar, özellikle hala harika bir neden olmadığını söyledi, o zamanlar hala yarı pişmişti - çok az JDK API'sinin yenilenmesi Charset'i kabul edin ve olanlardan Charset aşırı yükleri genellikle biraz daha kötü performans gösterdi.

Sadece JDK 1.6'da Charset aşırı yükleriyle her şeyi donatmayı bitirmeleri üzücü. Ve bu geriye dönük performans durumunun hala var olduğunu (inanılmaz derecede garip ve açıklayamıyorum, ancak güvenlikle ilgili!).

Uzun öykü kısa - sadece kendi sabitlerinizi tanımlayın veya Pony Tony'nin bağlı olduğu Guava'nın Charsets sınıfını kullanın (bu kütüphane henüz gerçekten yayınlanmamıştır).

Güncelleme: bir StandardCharsetssınıf JDK 7'de.


Sadece merak ediyorum, ne zaman Guava'nın bir sürümü (alfa / beta / ne olursa olsun) olacak? Proje ana sayfası bu konuda biraz kısadır.
Jonik

Çıkana kadar benim için türkiye yok!
Kevin Bourrillion

neden inanılmaz derecede garip ve bunu açıklayamıyorum, ancak güvenlik ile ilgili - özel karakter kümeleri aracılığıyla değiştirilebilir bir dize oluşturabilirsiniz, ancak onlar dize daha hızlı yapılmış olabilirdi (aslında charset görünüyor). Nasıl String(byte bytes[], int offset, int length, Charset charset)uygulandığı bir ihmal / ihmaldir . Aslında, büyük bir bayttan [] küçük bir dize oluştururken performans isabeti hiç de önemsiz değildir.
bestsss

7
Adil değil! Bu harika kaynaklara erişiminiz var. = (Bir zamanlar "Evet, bu yüzden Josh [Bloch] 'a bunu sordum ..."
dediğin

PrintStream
Charset'i

102

İki yıl sonra Java 7'nin StandardCharsets'i artık 6 standart karakter seti için sabitleri tanımladı.

Eğer Java 5/6 takılıp iseniz, Guava en kullanabilirsiniz Charsets Kevin Bourrillion ve Jon Skeet tarafından önerildiği gibi, sabitleri.


29

Bundan daha iyisini yapabileceğimizi iddia ediyorum ... neden temin edilebilir kullanılabilir karakter kümelerine doğrudan erişilemiyor? dizeye bir ad değil, Charset.UTF8bir referans olmalıdır Charset. Bu şekilde UnsupportedEncodingExceptionher yeri idare etmek zorunda kalmazdık .

Dikkat edin, ayrıca .NET'in her yerde UTF-8'e varsayılan olarak daha iyi bir strateji seçtiğini düşünüyorum. Daha sonra basitçe "işletim sistemi varsayılan" kodlama özelliğini adlandırarak berbat Encoding.Default- bu .NET'in kendisi için varsayılan değildir :(

Java'nın karakter seti desteği hakkında sıralamaya geri dönme - neden bir yapıcı yok FileWriter/ FileReaderhangisini alır Charset? Temel olarak bu kısıtlama nedeniyle neredeyse işe yaramaz sınıflardır - neredeyse her zaman çıktı için InputStreamReaderyaklaşık bir FileInputStreamveya eşdeğeri gerekir :(

Hemşire, hemşire - ilacım nerede?

EDIT: Bu soruya gerçekten cevap vermedi bana. Asıl cevap, muhtemelen "hiç kimse düşünmemişti" ya da "ilgili birisi kötü bir fikir olduğunu düşündü." Şiddetle içi yarar sınıfları kod temeli etrafında adları veya charsets önlemek tekrarını sağlayan öneririm ... Ya da sadece kullanabilirsiniz Bu cevap ilk yazıldığı zaman Google'da kullandığı tane . (Java 7'den itibaren StandardCharsetsbunun yerine sadece kullanacağınızı unutmayın .)


2
+1. Ancak tembel yüklemeye izin vermek için bir alan yerine bir yöntem olarak (tamam, muhtemelen UTF-8'i isteyeceksiniz, ancak hakkında birkaç karakter kümesi var ve onlar için benzer tesisler isteyebilirsiniz). Ne yazık ki bu, karar verenler arasında çok popüler görünmüyor.
Tom Hawtin - tackline

Bir yöntemle yeterince mutlu olurum, ancak bu çok az karakter setini hevesle yüklemenin önemli bir maliyet olmayacağını umuyorum.
Jon Skeet

1
İstekli sınıf yüklemesini durdurmak için bir haçlı seferi yapıyoruz. / "UTF-8" için JDK araması yaptım. Bulunan 270 dosya 165 dosya (lar) Bunların çoğu eski Apache önemsiz olsa da (ekibimin katkıda bulunduğuna inanıyorum).
Tom Hawtin - tackline

1
@tackline: Herhalde istekli sınıf yüklemesi zamanla artan şeylerden biri. Burada birkaç sınıf, birkaç sınıf var - her biri ayrı ayrı yeterince zararsız geliyor - büyük bir fark yaratabilir.
Jon Skeet

Guava Charsets ile son bağlantı koptu.
LarsH

28

Java 1.7'de

import java.nio.charset.StandardCharsets

örn: StandardCharsets.UTF_8 StandardCharsets.US_ASCII


5

Kodlama API'sinin geçerli durumu, istenen bir şey bırakıyor. Java 6 API bazı bölümleri kabul etmiyoruz Charset(bir dize yerine logging, dom.ls, PrintStream; başkaları da olabilir). Kodlamaların standart kütüphanenin farklı bölümleri için farklı kanonik adlara sahip olması beklenmez.

İşlerin bulundukları yere nasıl geldiğini anlayabiliyorum; Onları nasıl düzeltebileceğim konusunda parlak fikirlerim olduğundan emin değilim.


Bir yana ...

Sun'ın Java 6 uygulamasının adlarını burada bulabilirsiniz .

UTF-8 için, kanonik değerlerdir "UTF-8"için java.niove "UTF8"için java.langve java.io. Spesifikasyonun desteklenmesi için JRE gerektiren tek kodlama şunlardır: US-ASCII; ISO-8859-1; UTF-8; UTF-16BE; UTF-16LE; UTF-16 .


2
Sınıf açıkça "PrintWriter sınıfı bayt yerine karakter yazma gerektiren durumlarda kullanılmalıdır" diyor, PrintStream bir dilenmez. (Ki bu, tüm durumlar gibi ...)
Kevin Bourrillion

2

Uzun zaman önce UTF_8, ISO_8859_1 ve US_ASCII Karakter Kümesi sabitleriyle bir yardımcı sınıf tanımladım.

Ayrıca, önce bazı uzun süre (2+ yıl) Ben arasında basit performans test yaptım new String( byte[], Charset )ve new String( byte[], String charset_name )ve ikincisi uygulama olduğunu keşfetti ÖLÇÜDE daha hızlı. Kaynak koddaki başlık altına bakarsanız, aslında oldukça farklı bir yol izlediklerini göreceksiniz.

Bu nedenle aynı sınıfa bir yardımcı program ekledim

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

String (byte [], Charset) yapıcısı neden aynı şeyi yapmıyor, beni dövüyor.


1
Charsetİstisna olabilir böylece gerek tescil edilemez. IIRC'de, JDK7'de bilinen iyi Charsetuygulamaların daha hızlı olmasını sağlamak için bazı değişiklikler yapıldı (ekstra kopyayı ortadan kaldırın).
Tom Hawtin - tackline
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.