Laatste teken van een StringBuilder verwijderen?

Als je een verzameling moet doorlopen en een reeks moet maken van elke gegevens, gescheiden door een scheidingsteken, krijg je altijd een extra scheidingsteken aan het einde, bijvoorbeeld

for (String serverId : serverIds) {
  sb.append(serverId);
   sb.append(",");
}

Geeft zoiets als: serverId_1, serverId_2, serverId_3,

Ik wil het laatste teken in de StringBuilder verwijderen (zonder het te converteren omdat ik het na deze lus nog steeds nodig heb).


Antwoord 1, autoriteit 100%

Anderen hebben gewezen op de deleteCharAt-methode, maar hier is nog een alternatieve benadering:

String prefix = "";
for (String serverId : serverIds) {
  sb.append(prefix);
  prefix = ",";
  sb.append(serverId);
}

U kunt ook de Joinerles van Guava🙂

Vanaf Java 8, StringJoinermaakt deel uit van de standaard JRE.


Antwoord 2, autoriteit 70%

Een andere eenvoudige oplossing is:

sb.setLength(sb.length() - 1);

Een ingewikkelder oplossing:

De bovenstaande oplossing gaat ervan uit dat sb.length() > 0… d.w.z. er is een “laatste teken” om te verwijderen. Als je die veronderstelling niet kunt maken, en/of je niet kunt omgaan met de uitzondering die zou ontstaan ​​als de veronderstelling onjuist is, controleer dan eerst de lengte van de StringBuilder; bijv.

// Readable version
if (sb.length() > 0) {
   sb.setLength(sb.length() - 1);
}

of

// Concise but harder-to-read version of the above.
sb.setLength(Math.max(sb.length() - 1, 0));

Antwoord 3, autoriteit 29%

if(sb.length() > 0){
    sb.deleteCharAt(sb.length() - 1);
}

Antwoord 4, autoriteit 9%

Vanaf Java 8 heeft de klasse String een statische methode join. Het eerste argument is een string die je tussen elk paar strings wilt hebben, en het tweede is een Iterable<CharSequence>(die beide interfaces zijn, dus zoiets als List<String>werkt. Dus je kunt dit gewoon doen:

String.join(",", serverIds);

Ook in Java 8 kunt u de nieuwe StringJoinerklasse, voor scenario’s waarin je wilt beginnen met het construeren van de string voordat je de volledige lijst met elementen hebt om erin te plaatsen.


Antwoord 5, autoriteit 7%

Krijg gewoon de positie van het laatste teken dat voorkomt.

for(String serverId : serverIds) {
 sb.append(serverId);
 sb.append(",");
}
sb.deleteCharAt(sb.lastIndexOf(","));

Aangezien lastIndexOfeen omgekeerde zoekopdracht uitvoert, en u weet dat het bij de eerste poging zal vinden, zal de prestatie hier geen probleem zijn.

BEWERKEN

Omdat ik steeds weer ophef over mijn antwoord (bedankt mensen 😊), is het de moeite waard hierover:

Vanaf Java 8en later zou het alleen maar beter leesbaar en explicieter zijn om StringJoiner.
Het heeft één methode voor een eenvoudig scheidingsteken en een overbelasting voor voor- en achtervoegsel.

Voorbeelden van hier: voorbeeld

Voorbeeld met eenvoudig scheidingsteken:

   StringJoiner mystring = new StringJoiner("-");    
    // Joining multiple strings by using add() method  
    mystring.add("Logan");  
    mystring.add("Magneto");  
    mystring.add("Rogue");  
    mystring.add("Storm");  
    System.out.println(mystring);

Uitvoer:

Logan-Magneto-Rogue-Storm

Voorbeeld met achtervoegsel en voorvoegsel:

   StringJoiner mystring = new StringJoiner(",", "(", ")");    
    // Joining multiple strings by using add() method  
    mystring.add("Negan");  
    mystring.add("Rick");  
    mystring.add("Maggie");  
    mystring.add("Daryl");  
    System.out.println(mystring);

Uitvoer

(Negan,Rick,Maggie,Daryl)


Antwoord 6, autoriteit 5%

In dit geval,

sb.setLength(sb.length() - 1);

heeft de voorkeur omdat het alleen de laatste waarde toewijst aan '\0'terwijl het verwijderen van het laatste teken System.arraycopy

doet


Antwoord 7, autoriteit 2%

Met Java-8kunt u de statische methode van de klasse Stringgebruiken,

String#join(CharSequence delimiter,Iterable<? extends CharSequence> elements).


public class Test {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("James");
        names.add("Harry");
        names.add("Roy");
        System.out.println(String.join(",", names));
    }
}

UITVOER

James,Harry,Roy

Antwoord 8

Een ander alternatief

for(String serverId : serverIds) {
   sb.append(",");
   sb.append(serverId); 
}
sb.deleteCharAt(0);

Antwoord 9

Als alternatief,

StringBuilder result = new StringBuilder();
for(String string : collection) {
    result.append(string);
    result.append(',');
}
return result.substring(0, result.length() - 1) ;

Antwoord 10

StringBuilder sb = new StringBuilder();
sb.append("abcdef");
sb.deleteCharAt(sb.length() - 1);
assertEquals("abcde",sb.toString());
// true

Antwoord 11

Nog een alternatief:

public String join(Collection<String> collection, String seperator) {
    if (collection.isEmpty()) return "";
    Iterator<String> iter = collection.iterator();
    StringBuilder sb = new StringBuilder(iter.next());
    while (iter.hasNext()) {
        sb.append(seperator);
        sb.append(iter.next());
    }
    return sb.toString();
}

Antwoord 12

Gebruik TextUtils.isEmpty:

om het opnieuw invoeren (van invloed op de prestaties) van prefixte voorkomen

           String prefix = "";
            for (String item : list) {
                sb.append(prefix);
                if (TextUtils.isEmpty(prefix))
                    prefix = ",";
                sb.append(item);
            }

Antwoord 13

U kunt proberen de ‘Joiner’-klasse te gebruiken in plaats van het laatste teken uit uw gegenereerde tekst te verwijderen;

               List<String> textList = new ArrayList<>();
                textList.add("text1");
                textList.add("text2");
                textList.add("text3");
                Joiner joiner = Joiner.on(",").useForNull("null");
                String output = joiner.join(textList);
               //output : "text1,text2,text3"

Antwoord 14

Ik doe zoiets als hieronder:

   StringBuilder stringBuilder = new StringBuilder();
    for (int i = 0; i < value.length; i++) {
        stringBuilder.append(values[i]);
        if (value.length-1) {
            stringBuilder.append(", ");
        }
    }

Antwoord 15

Hier is een andere oplossing:

for(String serverId : serverIds) {
   sb.append(",");
   sb.append(serverId); 
}
String resultingString = "";
if ( sb.length() > 1 ) {
    resultingString = sb.substring(1);
}

Antwoord 16

stringBuilder.Remove(stringBuilder.Length – 1, 1);


Antwoord 17

Ik merkte dat ik dit nogal vaak deed, dus schreef ik een benchmark voor de 3 belangrijkste technieken voor het toevoegen van scheidingstekens:

(benchmark met de juiste warming-up en 100 ronden van 100.000 iteraties)

“Toevoegen na”

static void appendAfter()
{
    sb.append('{');
    for (int i = 0; i < 10; i++)
    {
        sb.append('"');
        sb.append(i);
        sb.append('"');
        sb.append(':');
        sb.append(i);
        sb.append(',');
    }
    sb.setLength(sb.length() - 1);
    sb.append('}');
}

“Vooraf toevoegen”

static void appendBefore()
{
    sb.append('{');
    String delimiter = "";
    for (int i = 0; i < 10; i++)
    {
        sb.append(delimiter);
        sb.append('"');
        sb.append(i);
        sb.append('"');
        sb.append(':');
        sb.append(i);
        delimiter = ",";
    }
    sb.append('}');
}

‘Misschien toevoegen’

static void appendMaybe()
{
    sb.append('{');
    for (int i = 0; i < 10; i++)
    {
        sb.append('"');
        sb.append(i);
        sb.append('"');
        sb.append(':');
        sb.append(i);
        if (i < 9)
        {
            sb.append(',');
        }
    }
    sb.append('}');
}

Ik heb de volgende resultaten:

Platform Toevoegen na Toevoegen voor Misschien toevoegen
Windows Server 2016, Java 11 – Hotspot 26ms 40ms 26ms
Windows Server 2016, Java 8 – Hotspot 27ms 36ms 21ms
Windows Server 2016, Java 11 – OpenJ9 63ms 81ms 59ms
Windows Server 2016, Java 8 – OpenJ9 66ms 64ms 55ms

Other episodes