2013-06-06 24 views
7

Stiamo utilizzando Java SAX per eseguire il parser su file XML molto grandi. Il nostro characters realizzazione appare come segue:Modo efficace di creare una stringa da char [], start, length in Java

@Override 
public void characters(char ch[], int start, int length) throws SAXException { 
    String value = String.copyValueOf(ch, start, length); 
    ... 
} 

(ch[] array passati dal SAX tendono ad essere piuttosto lungo)

Ma noi sono stati recentemente sempre alcuni problemi di prestazioni e il profiler ci mostra che oltre il 20% della nostra CPU l'utilizzo è sopra invocazione di String.copyValueOf (che ha invocato new String(ch,start,length) sotto il cofano).

Esiste un modo più efficace per ottenere una stringa dall'array di caratteri, iniziare l'indice e la lunghezza rispetto a String.copyValueOf(ch, start, length) o new String(ch,start,length)?

+0

Potrebbe essere peggio, ma hai provato un 'StringBuilder'? 'new String (ch, start, length)' copia solo l'array ma non so quanto velocemente un 'StringBuilder' funzioni. – Djon

+1

La stringa creata non viene restituita. Cosa fai con esso? Potrebbe quello che viene fatto con quella stringa anche essere fatto direttamente su char [] con start e length? – Fildor

+0

@ Fildor Sì, ci ho pensato. Ma facciamo molte diverse operazioni con esso dove lo trattiamo come stringhe. Sarebbe estremamente difficile (o almeno il codice sarebbe davvero brutto) operare su array di carri armati. –

risposta

4

Buona domanda, ma sono sicuro che la risposta è no.

Questo perché ogni costruzione di oggetto String utilizza il metodo di copia degli array. Non può essere costruito direttamente sull'array esistente, perché l'oggetto String deve essere immutabile e la sua rappresentazione di matrice di stringhe interna è incapsulata dalle modifiche esterne.

Inoltre, nel tuo caso hai un accordo con un frammento di qualche array. È impossibile creare l'oggetto String sul frammento di un altro array in alcun modo.

1

Come indicato da @Andremoniy, se si desidera utilizzare un oggetto String, è sempre necessario creare e copiare i contenuti in esso.

L'unica possibilità per accelerare il parser è ridurre al minimo il numero di oggetti stringa di nuova generazione.

Doppio che ogni elemento della struttura xml contiene dati non elaborati tra i tag di inizio e fine.

Pertanto, suggerisco di creare le stringhe solo se ci si trova all'interno di un elemento in cui i dati sono di interesse. Inoltre vorrei suggerire di limitare i possibili elementi in qualche modo. Ad esempio per livello gerarchico o elemento padre per ridurre il numero di stringhe. Ma questo dipende dalla struttura xml.

protected boolean readChars = false; 
protected int level = -1; 

@Override 
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { 
    ++level; 

    if (level == 4) { 
     if (qName.equalsIgnoreCase("TextElement")) { 
      readChars = true; 
     } 
    } 
} 

@Override 
public void characters(char ch[], int start, int length) throws SAXException { 
    if (readChars) { 
     String value = String.copyValueOf(ch, start, length); 
     ... 
     readChars = false; 
    } 
} 

@Override 
public void endElement(String uri, String localName, String qName) throws SAXException { 
    --level; 
} 
1

eventualmente insieme, che characters potrebbe essere chiamato più di una volta all'interno di una singola etichetta, in possesso di un StringBuilder a livello di elemento potrebbe essere appropriata. Questo fa un System.arrayCopy.