Issue with java8 lambda expression and foreach - java

I have a list like below
List<String> fruits = new ArrayList<>();
fruits.add("apple");
fruits.add("mango");
fruits.add("grapes");
System.out.println(fruits.toString());
I am using lambda expression for printing the list like
fruits.forEach(item->System.out.println(item));
and its working fine my requirement is I need to iterate over the list and concatenate the items to a string
String stringFruits = "";
fruits.forEach(item->stringFruits = stringFruits+item);
this is giving a compile time error saying variable values used in lambda should be effectively final is there any way I can do it in java 8 ?

You need to join via a delimiter. In this case the delimiter is going to be ,; but you can choose any you want.
String result = fruits.stream().collect(Collectors.joining(","));
System.out.println(result);

Java8 introduced a StringJoiner that does what you need (is another alternative to erans comment)
StringJoiner sj = new StringJoiner("-,-");
fruits.forEach(item -> sj.add(item));
here the doc
edit:
for the posterity you can do as well:
String result = fruits.stream().collect(Collectors.joining(","));
System.out.println(result);
or
String stringFruits = String.join(", ", fruits);
System.out.println(stringFruits);
credits and thanks to #Holger

You don’t need to do that by hand at all. If your source is a List, you can just use
String stringFruits = String.join(", ", fruits);
System.out.println(stringFruits);
The first argument to String.join(…) is the delimiter.

Or a pre-Java8 solution:
String combined = "";
for (String s : fruits) {
combined += s;
}
... and one with delimiter:
String combined = "";
for (String s : fruits) {
combined = combined + ", " + s;
}

Related

How to format a list of strings into [duplicate]

This question already has answers here:
Create formatted string from ArrayList
(7 answers)
Closed 3 years ago.
I have a list of strings that I want to format each of them in the same way. e.g. myListOfStrings = str1, str2, str3, and my format is (%s)
I want to have something like this:
String.format(" (%s) ", myListOfStrings)
Will output
(str1) (str2) (str3)
Is there an elegant way of doing this? or do I have to use a string builder and do a foreach loop on all the strings?
You can do this with Java 8:
import static java.util.stream.Collectors.joining;
public static void main(String[] args) throws Exception {
final List<String> strings = Arrays.asList("a", "b", "c");
final String joined = strings.stream()
.collect(joining(") (", "(", ")"));
System.out.println(joined);
}
Or:
final String joined = strings.stream()
.map(item -> "(" + item + ")")
.collect(joining(" "));
Which one you prefer is a matter of personal preference.
The first joins the items on ) ( which gives:
a) (b) (c
Then you use the prefix and suffix arguments to joining to with prefix with ( and suffix with ), to produce the right outcome.
The second alternative transforms each item to ( + item + ) and then joins them on " ".
The first might also be somewhat faster, as it only requires the creation of one StringBuilder instance - for both the join and the pre/suffix. The second alternative requires the creation of n + 1 StringBuilder instances, one for each element and one for the join on " ".
if you want a one-line solution, you could use one of the the StringUtils.join methods in Apache Commons Lang.
String result = "(" + StringUtils.join(myListOfStrings, ") (") + ")";
You can try this:
List<String> list = new ArrayList<String>();
list.add("str1");
list.add("str2");
list.add("str3");
for(String s : list) {
System.out.print(String.format(" (%s) ", s));
}
String strOut = "";
for(int i=0; i< myListOfStrings.size(); i++){
strOut = strOut +"("+myListOfStrings.get(i)+")";
}
Boris The Spider's answer is what I would go with, but in case you are not using java 8, but maybe you are using Guava you can do something like this, albeit it is a bit verbose:
Joiner.on("").join(Collections2.transform(myListOfStrings, new Function<String, String>() {
#Override
public String apply(String input) {
return String.format(" (%s) ", input);
}
}));
Using Java8 new forEach method for iterating over collections:
public static String format(List<String> list) {
StringBuilder sb = new StringBuilder();
list.forEach(x -> sb.append(String.format(" (%s) ", x)));
return sb.toString();
}
Try it here: https://ideone.com/52EKRH

Java string join to string

Assume i have List Collection of Strings and i want to loop by this List and add each element of List to some variable of type String.
List<String> words;
//assume words have 5 elements
String summary;//variable where i want to keep all elements
for (String word : words){
//here i want to add new word to the variable summary
}
As i know java always creates new object of String. Even if i try to change value - new object will be created anyway, am i right?
So here is a question how to join all elements of List in one variable?
On any version of Java:
Apache Commons has a class StringUtils that has a join method:
String result = StringUtils.join(words, ",")
On Java 8, you can do this natively. See this article.
use a StringBuilder to join all the words.
List<String> words;
//assume words have 5 elements
StringBuilder summary = new StringBuilder();
for (String word : words){
summary.append(word);
}
Finally, get the joined String with summary.toString().
Note : If you have an idea of the number of characters that would be appended to the StringBuilder, it will be more efficient to use the constructor that gets an initial size :
summary = new StringBuilder(size);.
I think the easiest solution would be to use a StringBuilder:
String summary;
List<String> words = ...;
StringBuilder builder = new StringBuilder();
for (String word : words) {
builder.append(word);
}
summary = builder.toString();
The simplest way would be to use an existing functionality, for example Apache Common's StringUtils.join(). If that's not possible, this will work:
StringBuilder sb = new StringBuilder();
for (String word : words) {
sb.append(word);
}
String summary = sb.toString();
You can try the following code,
List<String> words;
String summary = null;
for (String word : words)
{
summary = summary + word + " , ";
}
System.out.println("List items : " + summary);
An alternative to Apache commons (StringUtils) is Guava's Joiner.
For example:
List<String> words = new ArrayList<>();
words.add("word");
words.add("anotherWord");
String joinedWords = Joiner.on(",").join(words);
This may also be useful if you're not able to use Java 8.
See wiki:
https://github.com/google/guava/wiki/StringsExplained
As Eran suggest or just, use simple concatination
List<String> words;
//assume words have 5 elements
String summary = "";//variable where i want to keep all elements
for (String word : words){
summary = summary + word;
}
Have you looked at
StringUtils.join()
as a possible solution?
String summary = words.stream().collect( Collectors.joining() );
You can simply add.
summary += word;

Combine multiple strings into one JAVA

I have a set of strings which want to combine into one String with all sentences separated with coma like (*.csv)
here is how it goes with me:
String dataContainer;
for(String tempString:setInput){
String finalString = "," + tempString + "," ;
}
This doesn't work with me :(
But it should do for Set ex:
Set<String> setInput = new TreeSet();
setInput.add("Dog");
setInput.add("Cat");
setInput.add("Mouse");
to produce the string:
,Dog,,Cat,,Mouse,
It is better to use StringBuilder
StringBuilder sb= new StringBuilder();
for(String tempString:setInput){
sb.append(",").append(tempString).append(",");
}
Or we can use Java 8 Stream
String joined = Stream.of("A", "B", "C").collect(Collectors.joining("delimiter", "prefix", "suffix"));
Or use the StringJoiner class
Directly Use StringJoiner class
Or the StringBuilder class
new StringBuilder().add("A").add("B").toString()
What You are doing is intializing your result string each time.
Actually ,you want to do
String finalString ="";
for(String tempString:setInput){
finalString += "," + tempString + "," ;
}
But the above approach causes multiple String creations.
But I suggest to go for StringBuilder.
StringBuilder finalStringb =new StringBuilder();
for(String tempString:setInput){
finalStringb.append(",").append(tempString).append(",") ;
}
String finalS = finalStringb.toString();
Maybe you are looking only for
String csvString = "," + String.join(",,", string1, string2, string3) +"," ;
Reference
Solution 1: (If you don't need a delimiter)
I would recommend using concat(Object... objects) from org.assertj.core.util.String.
public static String concat(Object... objects) {
return Arrays.isNullOrEmpty(objects) ? null : (String)java.util.Arrays.stream(objects).map(String::valueOf).collect(Collectors.joining());
}
You can use it like this:
concat("string1", "string2", "string3", "string4");
Solution 2 using StringJoiner (Java 8+):
This is from java.util. You even have the option to specify a prefix and suffix.
StringJoiner stringJoiner = new StringJoiner(", ");
stringJoiner.add("string1");
stringJoiner.add("string2");
stringJoiner.add("string3");
assertEquals("string1, string2, string3", stringJoiner.toString());
Solution 3 using Collectors.joining (Java 8+):
This is a functionality from Java 8 Stream API.
List<String> stringList = Arrays.asList("string1", "string2", "string3");
String concatString = stringList.stream().collect(Collectors.joining(", "));
assertEquals("string1, string2, string3", concatString);
Alternatively, if you are using Java 8, you could try something like this:
public static String join(final Set<String> set){
return new StringBuilder(",").append(set.stream().collect(Collectors.joining(",,"))).append(",").toString();
}
public static void main(String args[]){
Set<String> setInput = new TreeSet<>();
setInput.add("Dog");
setInput.add("Cat");
setInput.add("Mouse");
System.out.println(join(setInput));
}
The output is:
,Cat,,Dog,,Mouse,
Although, I'm a little unsure to why you would want 2 commas in between each element and a comma at the start and end. If you just want one comma separating each element (and no comma at the start or end), modify the join(Set<String>) to look like this:
public static String join(final Set<String> set){
return set.stream().collect(Collectors.joining(",")); //change "," to ", " for spacing
}
After doing so, the new output would be:
Cat,Dog,Mouse
org.apache.commons.lang.StringUtils.join() can come in handy

Is there an easier way to collect strings from a collection of objects?

I have a collection of Ingredient objects for which I'd like get all their names (via getName()) and join them into a comma-delimited string. Currently my code looks like this:
public static String getIngredientList(Collection<Ingredient> ingredients) {
final Iterator<Ingredient> iterator = ingredients.iterator();
final String[] names = new String[ingredients.size()];
for (int i = 0; iterator.hasNext(); i++) {
names[i] = iterator.next().getName();
}
return TextUtils.join(", ", names);
}
I'm wondering if there's a more concise way to collect all the names into a String[] object. If this were Ruby, for example, it'd be easy to pull off a short one-liner to do exactly what I need:
ingredients.map(&:name).join(', ')
Using Eclipse Collections you can write the following using JDK 5 - 7:
MutableList<Ingredient> ingredients =
Lists.mutable.with(
new Ingredient("Flour"),
new Ingredient("Sugar"),
new Ingredient("Eggs"),
new Ingredient("Milk"));
MutableList<String> ingredientNames = ingredients.collect(new Function<Ingredient, String>()
{
public String valueOf(Ingredient ingredient)
{
return ingredient.getName();
}
});
String delimitedNames = ingredientNames.makeString(", ");
Assert.assertEquals("Flour, Sugar, Eggs, Milk", delimitedNames);
Using Java 8 with support for lambdas and method references you can compress it down to the following:
MutableList<Ingredient> ingredients =
Lists.mutable.with(
new Ingredient("Flour"),
new Ingredient("Sugar"),
new Ingredient("Eggs"),
new Ingredient("Milk"));
String delimitedNames =
ingredients.collect(Ingredient::getName).makeString(", ");
Assert.assertEquals("Flour, Sugar, Eggs, Milk", delimitedNames);
In this example, using the overloaded form of makeString() without parameters will result in the same string, as makeString() calls makeString(“, “).
String delimitedNames =
ingredients.collect(Ingredient::getName).makeString();
Assert.assertEquals("Flour, Sugar, Eggs, Milk", delimitedNames);
Note: I am a committer for Eclipse Collections.
Why don't you use a StringBuilder in the first place?
The relevant part of the code:
StringBuilder b = new StringBuilder();
for(Ingredient ingredient: ingredients) {
b.append(ingredient.getName() + ", ");
}
return b.toString();
Of course you have to remove the last ", " appended which can be done with using the substring method or not appending the last one.
StringBuilder result = new StringBuilder();
for(String string : collectionOfStrings) {
result.append(string);
result.append(",");
}
return result.length() > 0 ? result.substring(0, result.length() - 1): "";
see the duplicate post:
The most sophisticated way for creating comma-separated Strings from a Collection/Array/List?

Fastest way to put contents of Set<String> to a single String with words separated by a whitespace?

I have a few Set<String>s and want to transform each of these into a single String where each element of the original Set is separated by a whitespace " ".
A naive first approach is doing it like this
Set<String> set_1;
Set<String> set_2;
StringBuilder builder = new StringBuilder();
for (String str : set_1) {
builder.append(str).append(" ");
}
this.string_1 = builder.toString();
builder = new StringBuilder();
for (String str : set_2) {
builder.append(str).append(" ");
}
this.string_2 = builder.toString();
Can anyone think of a faster, prettier or more efficient way to do this?
With commons/lang you can do this using StringUtils.join:
String str_1 = StringUtils.join(set_1, " ");
You can't really beat that for brevity.
Update:
Re-reading this answer, I would prefer the other answer regarding Guava's Joiner now. In fact, these days I don't go near apache commons.
Another Update:
Java 8 introduced the method String.join()
String joined = String.join(",", set);
While this isn't as flexible as the Guava version, it's handy when you don't have the Guava library on your classpath.
If you are using Java 8, you can use the native
String.join(CharSequence delimiter, Iterable<? extends CharSequence> elements)
method:
Returns a new String composed of copies of the CharSequence elements joined together with a copy of the specified delimiter.
For example:
Set<String> strings = new LinkedHashSet<>();
strings.add("Java"); strings.add("is");
strings.add("very"); strings.add("cool");
String message = String.join("-", strings);
//message returned is: "Java-is-very-cool"
Set implements Iterable, so simply use:
String.join(" ", set_1);
As a counterpoint to Seanizer's commons-lang answer, if you're using Google's Guava Libraries (which I'd consider the 'successor' to commons-lang, in many ways), you'd use Joiner:
Joiner.on(" ").join(set_1);
with the advantage of a few helper methods to do things like:
Joiner.on(" ").skipNulls().join(set_1);
// If 2nd item was null, would produce "1, 3"
or
Joiner.on(" ").useForNull("<unknown>").join(set_1);
// If 2nd item was null, would produce "1, <unknown>, 3"
It also has support for appending direct to StringBuilders and Writers, and other such niceties.
Maybe a shorter solution:
public String test78 (Set<String> set) {
return set
.stream()
.collect(Collectors.joining(" "));
}
or
public String test77 (Set<String> set) {
return set
.stream()
.reduce("", (a,b)->(a + " " + b));
}
but native, definitely faster
public String test76 (Set<String> set) {
return String.join(" ", set);
}
I don't have the StringUtil library available (I have no choice over that) so using standard Java I came up with this ..
If you're confident that your set data won't include any commas or square brackets, you could use:
mySet.toString().replaceAll("\\[|\\]","").replaceAll(","," ");
A set of "a", "b", "c" converts via .toString() to string "[a,b,c]".
Then replace the extra punctuation as necesary.
Filth.
I use this method:
public static String join(Set<String> set, String sep) {
String result = null;
if(set != null) {
StringBuilder sb = new StringBuilder();
Iterator<String> it = set.iterator();
if(it.hasNext()) {
sb.append(it.next());
}
while(it.hasNext()) {
sb.append(sep).append(it.next());
}
result = sb.toString();
}
return result;
}
I'm confused about the code replication, why not factor it into a function that takes one set and returns one string?
Other than that, I'm not sure that there is much that you can do, except maybe giving the stringbuilder a hint about the expected capacity (if you can calculate it based on set size and reasonable expectation of string length).
There are library functions for this as well, but I doubt they're significantly more efficient.
This can be done by creating a stream out of the set and then combine the elements using a reduce operation as shown below (for more details about Java 8 streams check here):
Optional<String> joinedString = set1.stream().reduce(new
BinaryOperator<String>() {
#Override
public String apply(String t, String u) {
return t + " " + u;
}
});
return joinedString.orElse("");

Categories

Resources