You can actually use Collectors.joining(CharSequence delimiter,CharSequence prefix,CharSequence suffix) and you can look here for the API.
String values = list.stream().collect(Collectors.joining("','", "'", "'"));
Answer from Vasu on Stack OverflowYou can actually use Collectors.joining(CharSequence delimiter,CharSequence prefix,CharSequence suffix) and you can look here for the API.
String values = list.stream().collect(Collectors.joining("','", "'", "'"));
You can use the overload of Collectors.joining that takes prefix and suffix parameters.
String values = list.stream()
.collect(Collectors.joining("','", "'", "'"));
This will place single-quotes around all your values correctly, assuming that all of your values are strings that need single quotes for the syntax.
But, as is the case with all problems involving constructing a query by concatenating values, it leaves your vulnerable to SQL injection. A more secure and versatile solution involves using a PreparedStatement. Value placeholders are ? characters, and you can use various setXyz methods to set the values safely. It protects against SQL injection and allows for any data types to be used, not just string types.
You can use a regex
static String appendPrefixToEachLine(String prefix, String s) {
String ret = prefix + s.replaceAll("(\r\n|\n)", "$1" + prefix);
return ret.substring(0, ret.length() - prefix.length());
}
As @Holger mentions you can do this without a capturing group with
return prefix+s.replaceAll("(?:\r\n?|\n)(?!\\z)", "$0"+Matcher.quoteReplacement(prefix));
This regex says, find the places after a new line but not just before the end.
You asked for a Java 8 solution, but it's not necessary to use any Java 8 features for this. Here's how I'd do it:
static String prefixLines(String prefix, String input) {
return input.replaceAll(".*\\R|.+\\z", Matcher.quoteReplacement(prefix) + "$0");
}
I think matching entire lines (including a partial last line) makes things a bit easier than matching just line separators, as in Peter Lawrey's answer. Still, +1 for that. Also, kudos to Holger for mentioning quoteReplacement, which is very easy to forget.
Note that I've used \\R which matches any Unicode line break. However, this doesn't match the behavior of BufferedReader.readLine() in case that's important.
For one liners, use Java 8 Streams :
List<String> paths = DATA_TYPE.stream().map(c -> flow.value() + c.value()).collect(Collectors.toList());
If you must produce a LinkedList, you should use a different Collector.
Your implementation looks ok, but if you want something different, try this:
public static List<String> getData(final TypeFlow flow) {
return new AbstractList<String>() {
@Override
public String get(int index) {
return flow.value()+DATA_TYPE.get(index).value();
}
@Override
public int size() {
return DATA_TYPE.size();
}
};
}
This way you create a "virtual list" which does not actually contains data, but computes it on the fly.
Yes, this is possible using a custom Collector instance that will use an anonymous object with a count of items in the stream and an overloaded toString() method:
public String format(Stream<String> stream) {
return stream.collect(
() -> new Object() {
StringJoiner stringJoiner = new StringJoiner(",");
int count;
@Override
public String toString() {
return count == 1 ? stringJoiner.toString() : "[" + stringJoiner + "]";
}
},
(container, currentString) -> {
container.stringJoiner.add(currentString);
container.count++;
},
(accumulatingContainer, currentContainer) -> {
accumulatingContainer.stringJoiner.merge(currentContainer.stringJoiner);
accumulatingContainer.count += currentContainer.count;
}
).toString();
}
Explanation
Collector interface has the following methods:
public interface Collector<T,A,R> {
Supplier<A> supplier();
BiConsumer<A,T> accumulator();
BinaryOperator<A> combiner();
Function<A,R> finisher();
Set<Characteristics> characteristics();
}
I will omit the last method as it is not relevant for this example.
There is a collect() method with the following signature:
<R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super T> accumulator,
BiConsumer<R, R> combiner);
and in our case it would resolve to:
<Object> Object collect(Supplier<Object> supplier,
BiConsumer<Object, ? super String> accumulator,
BiConsumer<Object, Object> combiner);
- In the
supplier, we are using an instance ofStringJoiner(basically the same thing thatCollectors.joining()is using). - In the
accumulator, we are usingStringJoiner::add()but we increment the count as well - In the
combiner, we are usingStringJoiner::merge()and add the count to the accumulator - Before returning from
format()function, we need to calltoString()method to wrap our accumulatedStringJoinerinstance in[](or leave it as is is, in case of a single-element stream
The case for an empty case could also be added, I left it out in order not to make this collector more complicated.
There is already an accepted answer and I upvoted it too.
Still I would like to offer potentially another solution. Potentially because it has one requirement:
The stream.spliterator() of Stream<String> stream needs to be Spliterator.SIZED.
If that applies to your case, you could use also this solution:
public String format(Stream<String> stream) {
Spliterator<String> spliterator = stream.spliterator();
StringJoiner sj = spliterator.getExactSizeIfKnown() == 1 ?
new StringJoiner("") :
new StringJoiner(",", "[", "]");
spliterator.forEachRemaining(sj::add);
return sj.toString();
}
According to the JavaDoc Spliterator.getExactSizeIfKnown() "returns estimateSize() if this Spliterator is SIZED, else -1." If a Spliterator is SIZED then "estimateSize() prior to traversal or splitting represents a finite size that, in the absence of structural source modification, represents an exact count of the number of elements that would be encountered by a complete traversal."
Since "most Spliterators for Collections, that cover all elements of a Collection report this characteristic" (API Note in JavaDoc of SIZED) this could be the desired directer way.
EDIT:
If the Stream is empty we can return an empty String at once. If the Stream has only one String there is no need to create a StringJoiner and to copy the String to it. We return the single String directly.
public String format(Stream<String> stream) {
Spliterator<String> spliterator = stream.spliterator();
if (spliterator.getExactSizeIfKnown() == 0) {
return "";
}
if (spliterator.getExactSizeIfKnown() == 1) {
AtomicReference<String> result = new AtomicReference<String>();
spliterator.tryAdvance(result::set);
return result.get();
}
StringJoiner result = new StringJoiner(",", "[", "]");
spliterator.forEachRemaining(result::add);
return result.toString();
}