2009-04-10 24 views
10

Actualmente estoy usando split() para escanear a través de un archivo donde cada línea tiene el número de cadenas delimitadas por '~'. Leí en alguna parte que Scanner podría hacer un mejor trabajo con un archivo largo, en cuanto a rendimiento, así que pensé en echarle un vistazo.Escáner de Java vs String.split() frente a StringTokenizer; ¿Qué debería usar?

Mi pregunta es: ¿Tendría que crear dos instancias de Scanner? Es decir, ¿uno para leer una línea y otra basada en la línea para obtener tokens para un delimitador? Si tengo que hacerlo, dudo si obtendré alguna ventaja de su uso. Tal vez me estoy perdiendo algo aquí?

Respuesta

3

Yo diría que split() es el más rápido, y probablemente lo suficientemente bueno para lo que estás haciendo. Sin embargo, es menos flexible que scanner. StringTokenizer está en desuso y solo está disponible para compatibilidad con versiones anteriores, por lo que no lo use.

EDITAR: Siempre puede probar ambas implementaciones para ver cuál es más rápido. Tengo curiosidad por mí si scanner podría ser más rápido que split(). Split puede ser más rápido para un tamaño determinado VS Scanner, pero no puedo estar seguro de eso.

+0

Acepto que StringTokenizer posiblemente esté en desuso, pero no lo encontré en la lista de clases en desuso para j2se5 y java6. ¿Por qué? – gedevan

+0

StringTokenzier no está en desuso ... – Jon

+0

Tienes razón, no lo es.Pero desde la API: StringTokenizer es una clase heredada que se conserva por razones de compatibilidad, aunque se desaconseja su uso en el nuevo código. Se recomienda que cualquiera que busque esta funcionalidad use el método de división de String o el paquete java.util.regex en su lugar. – CookieOfFortune

6

Para la línea de procesamiento puede usar el escáner y para obtener fichas de cada línea puede usar división.

Scanner scanner = new Scanner(new File(loc)); 
try { 
    while (scanner.hasNextLine()){ 
     String[] tokens = scanner.nextLine().split("~"); 
     // do the processing for tokens here 
    } 
} 
finally { 
    scanner.close(); 
} 
5

Usted puede utilizar el método useDelimiter("~") que le permite iterar a través de las fichas en cada línea con hasNext()/next(), sin dejar de utilizar hasNextLine()/nextLine() para iterar a través de las mismas líneas.

EDIT: Si vas a hacer una comparación de rendimiento, debe pre-compilar la expresión regular cuando se hace la división() Prueba:

Pattern splitRegex = Pattern.compile("~"); 
while ((line = bufferedReader.readLine()) != null) 
{ 
    String[] tokens = splitRegex.split(line); 
    // etc. 
} 

Si utiliza String#split(String regex), se volverá a compilar la expresión regular cada vez. (Scanner almacena en caché automáticamente todas las expresiones regulares la primera vez que las compila). Si lo hace, no esperaría ver mucha diferencia en el rendimiento.

2

No necesita una expresión regular aquí, porque está dividiendo en una cadena fija. Apache StringUtilssplit se divide en cadenas simples.

Para divisiones de alto volumen, donde la división es el cuello de botella, en lugar de decir archivo IO, he encontrado que esto es hasta 10 veces más rápido que String.split(). Sin embargo, no lo probé contra una expresión regular compilada.

Guava también tiene un divisor, implementado en una forma más OO, pero me pareció que era significativamente más lento que StringUtils para divisiones de alto volumen.

8

Hice algunas métricas alrededor de estos en un modelo de un solo hilo y aquí están los resultados que obtuve.

 
~~~~~~~~~~~~~~~~~~Time Metrics~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
~ Tokenizer | String.Split() | while+SubString | Scanner | ScannerWithCompiledPattern ~ 
~ 4.0 ms |  5.1 ms  |  1.2 ms  |  0.5 ms |    0.1 ms   ~ 
~ 4.4 ms |  4.8 ms  |  1.1 ms  |  0.1 ms |    0.1 ms   ~ 
~ 3.5 ms |  4.7 ms  |  1.2 ms  |  0.1 ms |    0.1 ms   ~ 
~ 3.5 ms |  4.7 ms  |  1.1 ms  |  0.1 ms |    0.1 ms   ~ 
~ 3.5 ms |  4.7 ms  |  1.1 ms  |  0.1 ms |    0.1 ms   ~ 
____________________________________________________________________________________________________________ 

La salida viene escáner es que ofrece el mejor rendimiento, ahora los mismos debe ser evaluado en un modo de multiproceso! Uno de mis superiores dice que el Tokenizer da un pico de CPU y String.split no.

Cuestiones relacionadas