SORU
29 Temmuz 2010, PERŞEMBE


Neden Java en dize manipülasyonlar regexp dayanır?

Java tüm manipüle Dizeleri ile ne ilgisi var yöntemleri bir avuç vardır. En basit örnek, bir Dize.("bir şey") yöntemi. böl

Şimdi bu yöntemleri çoğu gerçek tanımını hepsi giriş parametre(ler) olarak bir düzenli ifade alır. Çok güçlü o zaman tüm yapı taşlarını yapar.

Şimdi bu yöntemleri çok göreceksin iki etkileri vardır:

  1. Bu yöntem çağrılır ifadesi her zaman yeniden derleyin. Gibi bir performans etkisi empoze.
  2. En "durumlarda bu yöntemler ile" "metin. sabit denir" gerçek hayat buldum Split yöntemi, en yaygın kullanımı daha da kötüsü: genellikle tek bir char ile deniyor (genellikle bir ','; 'ya da'&') tarafından bölünmüş.

Varsayılan yöntemleri güçlü olan değil, onlar da aslında ne amaçla kullanıldığını overpowered gibi görünüyor. Geliştirdik içten bir "fastSplit" sabit dizeleri böler yöntemi. Evde bir test eğer tek bir karakter olarak biliniyordu eğer bunu nasıl yapabileceğimi görmek için yazdım. Hem "standart" yöntem böl. daha önemli ölçüde daha hızlı

Bu yüzden merak ediyorum: neden Java API yolu seçti şimdi oldu mu? Split(char) ve split(String) ve splitRegex(Dizi) gibi bir şey olması yerine, bu gitmek için iyi bir sebep neydi ??


Güncelleme: birlikte ne kadar bir dize bölme, çeşitli şekillerde alacağını görmek için birkaç telefon görüşmesi tokat attım.

Kısa özet: bir yaparbüyükfark!

Her test çalışması için 10000000 yineleme, her zaman girişini kullanarak yaptım

"aap,noot,mies,wim,zus,jet,teun" 

ve her zaman kullanma ',' veya "," bölünme gibi bir tartışma.

Bu Linux sistemi (Atom D510 bir kutu var, biraz yavaş yani)::

fastSplit STRING
Test  1 : 11405 milliseconds: Split in several pieces
Test  2 :  3018 milliseconds: Split in 2 pieces
Test  3 :  4396 milliseconds: Split in 3 pieces

homegrown fast splitter based on char
Test  4 :  9076 milliseconds: Split in several pieces
Test  5 :  2024 milliseconds: Split in 2 pieces
Test  6 :  2924 milliseconds: Split in 3 pieces

homegrown splitter based on char that always splits in 2 pieces
Test  7 :  1230 milliseconds: Split in 2 pieces

String.split(regex)
Test  8 : 32913 milliseconds: Split in several pieces
Test  9 : 30072 milliseconds: Split in 2 pieces
Test 10 : 31278 milliseconds: Split in 3 pieces

String.split(regex) using precompiled Pattern
Test 11 : 26138 milliseconds: Split in several pieces 
Test 12 : 23612 milliseconds: Split in 2 pieces
Test 13 : 24654 milliseconds: Split in 3 pieces

StringTokenizer
Test 14 : 27616 milliseconds: Split in several pieces
Test 15 : 28121 milliseconds: Split in 2 pieces
Test 16 : 27739 milliseconds: Split in 3 pieces

Eğer char "böler." sabit bir yeri varsa, bu büyük bir fark yaratıyor gördüğünüz gibi

Size biraz fikir vermek için, şu anda bir veri Apache dosyalarından ve Hadoop arenada benimbüyükweb sitesi. Benim için bu şeyler gerçekten önemli :)

Çarpanlarına olmadığım bir şeyi buraya çöp toplayıcı. /../ Eşleştirici nesneleri bir sürü racak bir kalıp içine düzenli bir ifade derleme söyleyebileceğim kadarıyla, bu biraz zaman toplanması gerekir. Belki de uzun vadede bu sürümler arasındaki farkları daha da büyük olacaktır ...yani. ya da daha küçük.

Benim sonuca ulaştın:

  • Bu bölme dizeleri bir SÜRÜ varsa, sadece optimize etmek.
  • Eğer düzenli kullanırsanız yöntemleri eğer tekrar tekrar aynı modeli kullanmak her zaman derleme.
  • (Eski) StringTokenizer unutmayın
  • Eğer tek bir karakter üzerinde bölmek istiyorsanız o zaman özellikle eğer sadece parçaları belirli bir sayıda bölmek için gerekirse özel bir yöntemi kullanmak, (... 2 gibi).

P. S. ben tüm benim homegrown oynamak için char yöntemleri (bu sitede her şeyi altına düşen Lisans :) altında) tarafından bölünmüş veriyorum. Ben hiç bir zaman tam olarak .. henüz onları test. İyi eğlenceler.

private static String[]
        stringSplitChar(final String input,
                        final char separator) {
    int pieces = 0;

    // First we count how many pieces we will need to store ( = separators   1 )
    int position = 0;
    do {
        pieces  ;
        position = input.indexOf(separator, position   1);
    } while (position != -1);

    // Then we allocate memory
    final String[] result = new String[pieces];

    // And start cutting and copying the pieces.
    int previousposition = 0;
    int currentposition = input.indexOf(separator);
    int piece = 0;
    final int lastpiece = pieces - 1;
    while (piece < lastpiece) {
        result[piece  ] = input.substring(previousposition, currentposition);
        previousposition = currentposition   1;
        currentposition = input.indexOf(separator, previousposition);
    }
    result[piece] = input.substring(previousposition);

    return result;
}

private static String[]
        stringSplitChar(final String input,
                        final char separator,
                        final int maxpieces) {
    if (maxpieces <= 0) {
        return stringSplitChar(input, separator);
    }
    int pieces = maxpieces;

    // Then we allocate memory
    final String[] result = new String[pieces];

    // And start cutting and copying the pieces.
    int previousposition = 0;
    int currentposition = input.indexOf(separator);
    int piece = 0;
    final int lastpiece = pieces - 1;
    while (currentposition != -1 && piece < lastpiece) {
        result[piece  ] = input.substring(previousposition, currentposition);
        previousposition = currentposition   1;
        currentposition = input.indexOf(separator, previousposition);
    }
    result[piece] = input.substring(previousposition);

    // All remaining array elements are uninitialized and assumed to be null
    return result;
}

private static String[]
        stringChop(final String input,
                   final char separator) {
    String[] result;
    // Find the separator.
    final int separatorIndex = input.indexOf(separator);
    if (separatorIndex == -1) {
        result = new String[1];
        result[0] = input;
    }
    else {
        result = new String[2];
        result[0] = input.substring(0, separatorIndex);
        result[1] = input.substring(separatorIndex   1);
    }
    return result;
}

CEVAP
29 Temmuz 2010, PERŞEMBE


Normal ifade her zaman çekirdekler gerekmez unutmayın. Javadoc:

str.split(regex, n) formun bu yöntem bir çağırma ifadesi olarak aynı sonucu verir

Pattern.compile(regex).split(str, n) 

Eğer performans konusunda endişeleriniz varsa, desen derleme ve yeniden kullanabilirsiniz:

Pattern p = Pattern.compile(regex);
...
String[] tokens1 = p.split(str1); 
String[] tokens2 = p.split(str2); 
...

yerine

String[] tokens1 = str1.split(regex);
String[] tokens2 = str2.split(regex);
...

Bu API tasarımı için ana nedeni kolaylık olduğunu düşünüyorum. Düzenli ifadeler "dizeleri de bir karakter, birkaç yerine bir yöntem var API kolaylaştırır." sabit vardır beri Ve eğer birinin performansı hakkında endişeli ise normal ifade, hala yukarıda gösterildiği gibi önceden derlenmiş olabilir.

Benim hissettiğim herhangi bir istatistiksel kanıt ile geri alamam () çoğu zaman String.split() performans sorunu olmayan bir bağlamda kullanılır. E. g. bir kerelik bir eylem veya performans farkı diğer faktörlere göre önemsiz. IMO nadirdir performans optimizasyonu gerçekten mantıklı sıkı bir döngü, dizeleri kez aynı düzenli binlerce kullanarak bölünmüş durumda.

Karşılaştırma eşleştirici bu özel kıyasla karakter/performans görmek ilginç olurdu. Fark ayrı uygulanmasını haklı göstermek için yeterince büyük olmayabilir.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • BlackmillMusic

    BlackmillMus

    3 Kasım 2010
  • Philip DeFranco

    Philip DeFra

    16 EYLÜL 2006
  • The Onion

    The Onion

    14 Mart 2006