Pracując w aplikacji Java, niedawno musiałem utworzyć listę wartości rozdzielanych przecinkami, aby przekazać ją do innej usługi sieci Web, nie wiedząc z góry, ile elementów będzie. Najlepsze, co mogłem wymyślić z czubka głowy, to coś takiego:
public String appendWithDelimiter( String original, String addition, String delimiter ) {
if ( original.equals( "" ) ) {
return addition;
} else {
return original + delimiter + addition;
}
}
String parameterString = "";
if ( condition ) parameterString = appendWithDelimiter( parameterString, "elementName", "," );
if ( anotherCondition ) parameterString = appendWithDelimiter( parameterString, "anotherElementName", "," );
Zdaję sobie sprawę, że nie jest to szczególnie wydajne, ponieważ wszędzie są tworzone ciągi, ale chciałem uzyskać bardziej przejrzystość niż optymalizację.
W Ruby mogę zamiast tego zrobić coś takiego, co wydaje się znacznie bardziej eleganckie:
parameterArray = [];
parameterArray << "elementName" if condition;
parameterArray << "anotherElementName" if anotherCondition;
parameterString = parameterArray.join(",");
Ale ponieważ Java nie ma polecenia łączenia, nie mogłem znaleźć niczego równoważnego.
Więc jaki jest najlepszy sposób, aby to zrobić w Javie?
Odpowiedzi:
Przed Java 8:
Wspólny język Apache jest tutaj twoim przyjacielem - zapewnia on metodę łączenia bardzo podobną do tej, o której mówisz w Ruby:
StringUtils.join(java.lang.Iterable,char)
Java 8:
Java 8 zapewnia dołączanie od razu po wyjęciu z pudełka za pomocą
StringJoiner
iString.join()
. Poniższe fragmenty pokazują, jak możesz ich używać:StringJoiner
String.join(CharSequence delimiter, CharSequence... elements))
String.join(CharSequence delimiter, Iterable<? extends CharSequence> elements)
źródło
Możesz napisać małą metodę narzędzia w stylu łączenia, która działa na java.util.Lists
Następnie użyj go w następujący sposób:
źródło
List<String>
intitializatora naIterator<?>
taki sam efekt?W przypadku Androida klasa StringUtils ze wspólnych nie jest dostępna, więc do tego użyłem
http://developer.android.com/reference/android/text/TextUtils.html
źródło
The Google Guava ma klasę com.google.common.base.Joiner, która pomaga rozwiązać takie zadania.
Próbki:
Oto artykuł o narzędziach strunowych Guavy .
źródło
W Javie 8 możesz używać
String.join()
:Zobacz także tę odpowiedź na przykład interfejsu API Stream.
źródło
Możesz to uogólnić, ale jak już mówisz, nie ma możliwości łączenia w Javie.
To może działać lepiej.
źródło
Iterable<String>
i po prostu skorzystaj z faktu, że możesz iterować nad nim. W twoim przykładzie nie potrzebujesz liczby elementów w kolekcji, więc jest to jeszcze bardziej ogólne.StringBuilder
zamiast tego użyć . Są identyczne, z wyjątkiem tego, żeStringBuffer
zapewniają niepotrzebne bezpieczeństwo wątku. Czy ktoś może to edytować!isEmpty()
metody,next()
zamiast niej użyj metodyw Javie 8 możesz to zrobić w następujący sposób:
jeśli lista zawiera wartości null, możesz użyć:
obsługuje także przedrostek i przyrostek:
źródło
Zastosuj podejście oparte na
java.lang.StringBuilder
! („Zmienna sekwencja znaków.”)Jak już wspomniałeś, wszystkie te kombinacje ciągów tworzą ciągi znaków w całym tekście.
StringBuilder
nie zrobię tego.Dlaczego
StringBuilder
zamiastStringBuffer
? ZStringBuilder
javadoc:źródło
Użyłbym kolekcji Google. Jest fajny obiekt Join.
http://google-collections.googlecode.com/svn/trunk/javadoc/index.html?com/google/common/base/Join.html
Ale gdybym chciał napisać to sam,
Myślę, że to działa lepiej z kolekcją obiektów, ponieważ teraz nie musisz konwertować swoich obiektów na łańcuchy przed dołączeniem do nich.
źródło
Apache commons Klasa StringUtils ma metodę łączenia.
źródło
Java 8
źródło
Możesz do tego użyć typu Java
StringBuilder
. Jest teżStringBuffer
, ale zawiera dodatkową logikę bezpieczeństwa wątków, która często jest niepotrzebna.źródło
I minimalny (jeśli nie chcesz uwzględniać Apache Commons lub Gauva w zależnościach projektu tylko ze względu na łączenie łańcuchów)
źródło
Użyj StringBuilder i klasy
Separator
Separator otacza separator. Separator jest zwracany przez separator
toString
, chyba że przy pierwszym wywołaniu, które zwraca pusty ciąg!Kod źródłowy dla klasy
Separator
źródło
Separator
aby używałaStringBuilder
zamiast konkatenacjiStrings
?Separator
po prostu zwraca ogranicznik, nie konkatenuje samego łańcucha.Separator
? Dlaczego nie użyć zwykłego ciągu ..?!Dlaczego nie napisać własnej metody join ()? Przyjmie to jako zbiór parametrów ciągów i ogranicznika ciąg. W ramach metody iteruj po kolekcji i buduj swój wynik w StringBuffer.
źródło
Jeśli korzystasz z Spring MVC, możesz spróbować wykonać następujące kroki.
Spowoduje to
a,b,c
źródło
Jeśli korzystasz z kolekcji Eclipse , możesz użyć
makeString()
lubappendString()
.makeString()
zwracaString
reprezentację podobną dotoString()
.Ma trzy formy
makeString(start, separator, end)
makeString(separator)
domyślnie początek i koniec do pustych ciągówmakeString()
domyślnie separator to", "
(przecinek i spacja)Przykład kodu:
appendString()
jest podobny domakeString()
, ale dołącza się doAppendable
(jakStringBuilder
) i jestvoid
. Ma te same trzy formy, z dodatkowym pierwszym argumentem, Appendable.Jeśli nie możesz przekonwertować swojej kolekcji na typ kolekcji Eclipse, po prostu dostosuj ją za pomocą odpowiedniego adaptera.
Uwaga: jestem osobą odpowiedzialną za kolekcje Eclipse.
źródło
Typ macierzysty Java 8
Obiekt niestandardowy Java 8:
źródło
Powinieneś użyć
StringBuilder
zappend
metodą skonstruować swój wynik, ale poza tym to jest tak dobra, jak rozwiązania Java ma do zaoferowania.źródło
Dlaczego nie robisz w Javie tego samego, co robisz w Rubim, czyli tworzy ciąg rozdzielany separatorem dopiero po dodaniu wszystkich elementów do tablicy?
Możesz przenieść to dla pętli w osobnej metodzie pomocnika, a także użyć StringBuilder zamiast StringBuffer ...
Edycja : poprawiono kolejność dołączeń.
źródło
Dzięki zmiennym argumentom Java 5, więc nie musisz jawnie upychać wszystkich swoich ciągów do kolekcji lub tablicy:
źródło
Dla tych, którzy są w kontekście wiosennym, ich StringUtils przydatna jest również klasa :
Istnieje wiele przydatnych skrótów, takich jak:
i wiele innych.
Może to być pomocne, jeśli nie używasz już Java 8 i jesteś już w kontekście Spring.
Wolę to niż Apache Commons (choć również bardzo dobre) ze względu na obsługę Kolekcji, która jest łatwiejsza w następujący sposób:
źródło
Możesz spróbować czegoś takiego:
źródło
Więc w zasadzie coś takiego:
źródło
Nie wiem, czy to naprawdę jest lepsze, ale przynajmniej używa StringBuilder, który może być nieco bardziej wydajny.
Poniżej znajduje się bardziej ogólne podejście, jeśli możesz zbudować listę parametrów PRZED wykonaniem jakiegokolwiek ograniczania parametrów.
źródło
Twoje podejście nie jest takie złe, ale powinieneś użyć StringBuffer zamiast znaku +. + Ma tę dużą wadę, że tworzona jest nowa instancja String dla każdej pojedynczej operacji. Im dłuższy ciąg, tym większe obciążenie. Zatem użycie StringBuffer powinno być najszybszym sposobem:
Po zakończeniu tworzenia łańcucha po prostu wywołaj metodę toString () na zwróconym StringBuffer.
źródło
Zamiast korzystać z konkatenacji łańcuchów, należy użyć StringBuilder, jeśli kod nie jest wątkowy, i StringBuffer, jeśli tak jest.
źródło
Sprawiasz, że jest to trochę bardziej skomplikowane, niż musi być. Zacznijmy od końca twojego przykładu:
Przy niewielkiej zmianie przy użyciu StringBuilder zamiast String, staje się to:
Kiedy skończysz (zakładam, że musisz również sprawdzić kilka innych warunków), po prostu upewnij się, że usunąłeś przecinek końcowy za pomocą polecenia:
I wreszcie, weź ciąg, który chcesz
Możesz również zastąpić „,” w drugim wywołaniu, aby dołączyć ogólny ciąg separatora, który można ustawić na dowolny. Jeśli masz listę rzeczy, które musisz dołączyć (bezwarunkowo), możesz umieścić ten kod w metodzie, która pobiera listę ciągów.
źródło
źródło
Kilka rzeczy, które możesz zrobić, aby mieć wrażenie, że szukasz:
1) Rozszerz klasę listy - i dodaj do niej metodę łączenia. Metoda łączenia po prostu wykona pracę polegającą na konkatenacji i dodaniu separatora (który może być paramem do metody łączenia)
2) Wygląda na to, że Java 7 będzie dodawać metody rozszerzeń do java - co pozwala po prostu dołączyć konkretną metodę do klasy: abyś mógł napisać tę metodę łączenia i dodać ją jako metodę rozszerzenia do listy, a nawet do Kolekcja.
Rozwiązanie 1 jest prawdopodobnie jedynym realistycznym, jednak ponieważ Java 7 nie jest jeszcze dostępna :) Ale powinno działać dobrze.
Aby użyć obu tych elementów, wystarczy zwyczajnie dodać wszystkie swoje elementy do listy lub kolekcji, a następnie wywołać nową niestandardową metodę, aby je „dołączyć”.
źródło