2013-02-15 5 views
13

jako stanów zapytania podanych następujący kod:Java String.split przechodzą w skompilowany regex wykonania powodów

public class Foo 
{ 
    public static void main(String[] args) 
    { 
     String test = "Cats go meow"; 
     String[] tokens = test.split(" "); 
    } 
} 

jest to możliwe do precompile że regex w funkcji podziału wzdłuż linii to:

public class Foo 
{ 
    Pattern pattern = Pattern.compile(" "); 
    public static void main(String[] args) 
    { 
     String test = "Cats go meow"; 
     String[] tokens = test.split(pattern); 
    } 
} 
+0

split ("") jest szybszy (patrz komentarz poniżej) –

+0

@michael_s Dodałem komentarz, proszę odliczać. – Woot4Moo

Odpowiedz

17

Tak, jest to możliwe. Wykonaj także statyczną liczbę pattern, aby statyczna metoda mogła uzyskać do niej dostęp.

public class Foo 
{ 
    private static Pattern pattern = Pattern.compile(" "); 
    public static void main(String[] args) 
    { 
     String test = "Cats go meow"; 
     String[] tokens = pattern.split(test); 
    } 
} 

Według docs dla metody STRING split, można użyć struny split lub wzór na split, ale struny split kompiluje Pattern i wywołuje jego metodę split, więc używaj Pattern do precompile regex.

+0

Tak "Rozdzielenie # wzoru (ciąg)" jest około 25% szybsze. Zobacz perf benchmark firmy Oracle (slajd 72) https://shipilev.net/talks/joker-Oct2014-string-catechism.pdf – ruhong

3

Zastosowanie Pattern.split() zamiast:

String[] tokens = pattern.split(test); 
+0

hmm w rzeczywistości nie dotyczy to wstępnego kompilowania wzorca, ponieważ jest to etap kompilacji, który zajmuje "najwięcej" czasu. – Woot4Moo

+0

@ Woot4Moo: Nie rozumiem twojej ostatniej uwagi. Gdy masz instancję 'Pattern', regex został skompilowany, a' pattern.split() 'nie wymaga dalszej kompilacji. – NPE

+0

Mój błąd Pomyślałem, że istnieje sposób na samodzielne tworzenie wzoru. – Woot4Moo

5
public class Foo 
{ 
    private static final Pattern pattern = Pattern.compile(" "); 
    public static void main(String[] args) 
    { 
     String test = "Cats go meow"; 
     String[] tokens = pattern.split(test); 
    } 
} 
+1

Należy również rozważyć nadanie statycznemu i ostatecznemu schematu. Zapisałoby to narzut kompilacji dla każdego wystąpienia. – Rohit

3

Nie - myślę, że to byłby zły pomysł!

Patrząc z bliska na kodzie źródłowym dzielonej metody - jest skrótem wdrożone w przypadku ciąg jest tylko jeden znak (i ​​nie zawiera znaku regex specjalna)

public String[] split(String regex, int limit) { 
    /* fastpath if the regex is a 
    (1)one-char String and this character is not one of the 
     RegEx's meta characters ".$|()[{^?*+\\", or 
    (2)two-char String and the first char is the backslash and 
     the second is not the ascii digit or ascii letter. 
    */ 
    char ch = 0; 
    if (((regex.value.length == 1 && 
     ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) || 

tak - split ("") powinien być dużo szybszy.

Z drugiej strony podczas używania wyrażeń regularnych zawsze dobrze jest zrobić z nich statyczne elementy końcowe.

edit:

Kod źródłowy JDK1.7 i OpenJDK 7 wydaje się być identyczna dla String.split - mają siebie spojrzeć: Lines 2312ff.

SO - dla bardziej skomplikowanych wzorów (1 lub więcej spacji na przykład):

static final Pattern pSpaces = Pattern.compile("[ ]+"); 
+0

hmm Konkurs, że String.split wewnątrz pętli while unieważniłoby to roszczenie. Chcesz się odpierać? – Woot4Moo

+0

Nie rozumiem, co masz na myśli - co podczas pętli? –

+0

tylko dlatego, że mój program nie ilustruje pętli 'while' nie oznacza, że ​​inne programy nie mają ich. Gdybym napisał parser, który musiałby tokenizować serię linii, byłaby pętla 'while' – Woot4Moo