Oto eleganckie rozwiązanie używając API strumieni:
String nameList = names.stream().collect(naturalCollector(", ", " and "));
Unfortunatley, zależy to od tej funkcji, które można schować w jakimś klasie użytkowej:
public static Collector<Object, Ack, String> naturalCollector(String sep, String lastSep) {
return new Collector<Object, Ack, String>() {
@Override public BiConsumer<Ack, Object> accumulator() {
return (Ack a, Object o) -> a.add(o, sep);
}
@Override public Set<java.util.stream.Collector.Characteristics> characteristics() {
return Collections.emptySet();
}
@Override public BinaryOperator<Ack> combiner() {
return (Ack one, Ack other) -> one.merge(other, sep);
}
@Override public Function<Ack, String> finisher() {
return (Ack a) -> a.toString(lastSep);
}
@Override public Supplier<Ack> supplier() {
return Ack::new;
}
};
}
... i także w tej klasie, która jest wewnętrznym stateholder w powyższej funkcji, ale które API Collector chce narażone:
class Ack {
private StringBuilder result = null;
private Object last;
public void add(Object u, String sep) {
if (last != null) {
doAppend(sep, last);
}
last = u;
}
private void doAppend(String sep, Object t) {
if (result == null) {
result = new StringBuilder();
} else {
result.append(sep);
}
result.append(t);
}
public Ack merge(Ack other, String sep) {
if (other.last != null) {
doAppend(sep, last);
if (other.result != null) {
doAppend(sep, other.result);
}
last = other.last;
}
return this;
}
public String toString(String lastSep) {
if (result == null) {
return last == null ? "" : String.valueOf(last);
}
result.append(lastSep).append(last);
return result.toString();
}
}
Czy przecinki są zawsze w obrębie wartości? – Bohemian
@Behemian nope (zauważył, że w pytaniu) – Xorty
Dlaczego nie enkapsulować jego funkcjonalności w metodzie zewnętrznej? Coś w stylu 'public String mixListOfNamesAndReplaceLastCommaWithAnd (lista nazw)' –
Anatoly