I have the below code which is bit ugly for multiple null checks.
String s = null;
if (str1 != null) {
s = str1;
} else if (str2 != null) {
s = str2;
} else if (str3 != null) {
s = str3;
} else {
s = str4;
}
So I tried using Optional.ofNullable like below, but its still difficult to understand if someone reads my code. what is the best approach to do that in Java 8.
String s = Optional.ofNullable(str1)
.orElse(Optional.ofNullable(str2)
.orElse(Optional.ofNullable(str3)
.orElse(str4)));
In Java 9, we can use Optional.ofNullablewith OR, But in Java8 is there any other approach ?
You may do it like so:
String s = Stream.of(str1, str2, str3)
.filter(Objects::nonNull)
.findFirst()
.orElse(str4);
How about ternary conditional operator?
String s =
str1 != null ? str1 :
str2 != null ? str2 :
str3 != null ? str3 : str4
;
You can also use a loop:
String[] strings = {str1, str2, str3, str4};
for(String str : strings) {
s = str;
if(s != null) break;
}
Current answers are nice but you really should put that in a utility method:
public static Optional<String> firstNonNull(String... strings) {
return Arrays.stream(strings)
.filter(Objects::nonNull)
.findFirst();
}
That method has been in my Util class for years, makes code much cleaner:
String s = firstNonNull(str1, str2, str3).orElse(str4);
You can even make it generic:
#SafeVarargs
public static <T> Optional<T> firstNonNull(T... objects) {
return Arrays.stream(objects)
.filter(Objects::nonNull)
.findFirst();
}
// Use
Student student = firstNonNull(student1, student2, student3).orElseGet(Student::new);
I use a helper function, something like
T firstNonNull<T>(T v0, T... vs) {
if(v0 != null)
return v0;
for(T x : vs) {
if (x != null)
return x;
}
return null;
}
Then this kind of code can be written as
String s = firstNonNull(str1, str2, str3, str4);
A solution which can be applied to as many element as you want can be :
Stream.of(str1, str2, str3, str4)
.filter(Object::nonNull)
.findFirst()
.orElseThrow(IllegalArgumentException::new)
You could imagine a solution like below, but the first one ensures non nullity for all of the elements
Stream.of(str1, str2, str3).....orElse(str4)
You can also lump up all the Strings into an array of String then do a for loop to check and break from the loop once it's assigned.
Assuming s1, s2, s3, s4 are all Strings.
String[] arrayOfStrings = {s1, s2, s3};
s = s4;
for (String value : arrayOfStrings) {
if (value != null) {
s = value;
break;
}
}
Edited to throw in condition for default to s4 if none is assigned.
Method based and simple.
String getNonNull(String def, String ...strings) {
for(int i=0; i<strings.length; i++)
if(strings[i] != null)
return s[i];
return def;
}
And use it as:
String s = getNonNull(str4, str1, str2, str3);
It's simple to do with arrays and looks pretty.
If you use Apache Commons Lang 3 then it can be written like this:
String s = ObjectUtils.firstNonNull(str1, str2, str3, str4);
Use of ObjectUtils.firstNonNull(T...) was taken from this answer. Different approaches were also presented in related question.
Using of a for loop will be the most suitable solution, as all beginner and experienced developers have enough knowledge of Loops. It's quite simple, first make an array, and then check the entries one by one. If any nonNull string found then stop the loop, and proceed to the results.
String[] myData = {s1, s2, s3, s4};
String s = null;
for (String temp : myData) {
if (temp != null) {
s = temp;
break;
}
}
Now you can track the nonNull value of the string, or can check if all strings were null, by using the below code.
if(s != null)
System.out.println(s);
else
System.out.println("All Strings are null");
Related
Consider the following keys (under_score) and fields (lowerCamel):
keys = ["opened_by","ticket_owner","close_reason"]
fields = ["openedBy","ticketOwner","closeReason"]
I'm looking for an efficient way in Java to check whether key is in fields, where I expect the following to return true:
fields = ["openedBy","ticketOwner"]
return fields.contains("opened_by")) //true
My code:
Set<String> incidentFields = Arrays
.stream(TicketIncidentDTO.class.getDeclaredFields())
.map(Field::getName)
.collect(Collectors.toSet()
);
responseJson.keySet().forEach(key ->{
if (incidentFields.contains(key))
{
//Do something
}
});
I could just replace all lowerCase with underscore, but I'm looking for more efficient way of doing this.
Try with CaseUtils from Commons Text
// opened_by -> openedBy
private String toCamel(String str) {
return CaseUtils.toCamelCase(str, false, new char[] { '_' });
}
List<String> keys = Arrays.asList("opened_by", "ticket_owner", "close_reason", "full_name");
List<String> fields = Arrays.asList("openedBy", "ticketOwner", "closeReason");
keys.forEach(t -> {
// check
if (fields.contains(toCamel(t))) {
System.out.println(t);
}
});
If you do not have fields like abcXyz (abc_xyz) and abCxyz (ab_cxyz) (fields with same spelling but combination of different words), then one solution would be to replace the "_" with empty "" and then compare to fieldName using equalsIgnoreCase. Another but similar solution would be to convert each fieldName to lower case and then compare it to the camel case string after replacing the "_" with "". This could possibly eliminate the use of an additional loop when compared to the first approach.
Set<String> fields= Arrays.stream(TicketIncidentDTO.class.getDeclaredFields())
.map(Field::getName)
.map(String::toLowerCase)
.collect(Collectors.toSet());
responseJson.keySet()
.filter(key -> fields.contains(key.replaceAll("_","")))
.forEach(key -> {
// do something..
});
A simple toCamel method:
private String toCamel(String str) {
String[] parts = str.split("_");
StringBuilder sb = new StringBuilder(parts[0]);
for (int i=1; i < parts.length ; i++) {
String part = parts[i];
if (part.length() > 0) {
sb.append(part.substring(0, 1).toUpperCase()).append(part.substring(1));
}
}
return sb.toString();
}
Now use the very same approach:
keys.forEach(t -> {
if (fields.contains(toCamel(t))) {
System.out.println("Fields contain " + t);
} else {
System.out.println("Fields doesn't contain " + t);
}
});
I could just replace all lowerCase with underscore, but I'm looking for more efficient way of doing this.
Use Set as a data structure for keys and fields that is very effective in the look-up. Moreover, it is sutable for this use case since it doesn't make sense to have duplicated keys in JSON.
I want the Java code for converting an array of strings into an string.
Java 8+
Use String.join():
String str = String.join(",", arr);
Note that arr can also be any Iterable (such as a list), not just an array.
If you have a Stream, you can use the joining collector:
Stream.of("a", "b", "c")
.collect(Collectors.joining(","))
Legacy (Java 7 and earlier)
StringBuilder builder = new StringBuilder();
for(String s : arr) {
builder.append(s);
}
String str = builder.toString();
Alternatively, if you just want a "debug-style" dump of an array:
String str = Arrays.toString(arr);
Note that if you're really legacy (Java 1.4 and earlier) you'll need to replace StringBuilder there with StringBuffer.
Android
Use TextUtils.join():
String str = TextUtils.join(",", arr);
General notes
You can modify all the above examples depending on what characters, if any, you want in between strings.
DON'T use a string and just append to it with += in a loop like some of the answers show here. This sends the GC through the roof because you're creating and throwing away as many string objects as you have items in your array. For small arrays you might not really notice the difference, but for large ones it can be orders of magnitude slower.
Use Apache commons StringUtils.join(). It takes an array, as a parameter (and also has overloads for Iterable and Iterator parameters) and calls toString() on each element (if it is not null) to get each elements string representation. Each elements string representation is then joined into one string with a separator in between if one is specified:
String joinedString = StringUtils.join(new Object[]{"a", "b", 1}, "-");
System.out.println(joinedString);
Produces:
a-b-1
I like using Google's Guava Joiner for this, e.g.:
Joiner.on(", ").skipNulls().join("Harry", null, "Ron", "Hermione");
would produce the same String as:
new String("Harry, Ron, Hermione");
ETA: Java 8 has similar support now:
String.join(", ", "Harry", "Ron", "Hermione");
Can't see support for skipping null values, but that's easily worked around.
From Java 8, the simplest way I think is:
String[] array = { "cat", "mouse" };
String delimiter = "";
String result = String.join(delimiter, array);
This way you can choose an arbitrary delimiter.
You could do this, given an array a of primitive type:
StringBuffer result = new StringBuffer();
for (int i = 0; i < a.length; i++) {
result.append( a[i] );
//result.append( optional separator );
}
String mynewstring = result.toString();
Try the Arrays.deepToString method.
Returns a string representation of the "deep contents" of the specified
array. If the array contains other arrays as elements, the string
representation contains their contents and so on. This method is
designed for converting multidimensional arrays to strings
Try the Arrays.toString overloaded methods.
Or else, try this below generic implementation:
public static void main(String... args) throws Exception {
String[] array = {"ABC", "XYZ", "PQR"};
System.out.println(new Test().join(array, ", "));
}
public <T> String join(T[] array, String cement) {
StringBuilder builder = new StringBuilder();
if(array == null || array.length == 0) {
return null;
}
for (T t : array) {
builder.append(t).append(cement);
}
builder.delete(builder.length() - cement.length(), builder.length());
return builder.toString();
}
public class ArrayToString
{
public static void main(String[] args)
{
String[] strArray = new String[]{"Java", "PHP", ".NET", "PERL", "C", "COBOL"};
String newString = Arrays.toString(strArray);
newString = newString.substring(1, newString.length()-1);
System.out.println("New New String: " + newString);
}
}
You want code which produce string from arrayList,
Iterate through all elements in list and add it to your String result
you can do this in 2 ways: using String as result or StringBuffer/StringBuilder.
Example:
String result = "";
for (String s : list) {
result += s;
}
...but this isn't good practice because of performance reason. Better is using StringBuffer (threads safe) or StringBuilder which are more appropriate to adding Strings
String[] strings = new String[25000];
for (int i = 0; i < 25000; i++) strings[i] = '1234567';
String result;
result = "";
for (String s : strings) result += s;
//linear +: 5s
result = "";
for (String s : strings) result = result.concat(s);
//linear .concat: 2.5s
result = String.join("", strings);
//Java 8 .join: 3ms
Public String join(String delimiter, String[] s)
{
int ls = s.length;
switch (ls)
{
case 0: return "";
case 1: return s[0];
case 2: return s[0].concat(delimiter).concat(s[1]);
default:
int l1 = ls / 2;
String[] s1 = Arrays.copyOfRange(s, 0, l1);
String[] s2 = Arrays.copyOfRange(s, l1, ls);
return join(delimiter, s1).concat(delimiter).concat(join(delimiter, s2));
}
}
result = join("", strings);
// Divide&Conquer join: 7ms
If you don't have the choise but to use Java 6 or 7 then you should use Divide&Conquer join.
String array[]={"one","two"};
String s="";
for(int i=0;i<array.length;i++)
{
s=s+array[i];
}
System.out.print(s);
Use Apache Commons' StringUtils library's join method.
String[] stringArray = {"a","b","c"};
StringUtils.join(stringArray, ",");
When we use stream we do have more flexibility, like
map --> convert any array object to toString
filter --> remove when it is empty
join --> Adding joining character
//Deduplicate the comma character in the input string
String[] splits = input.split("\\s*,\\s*");
return Arrays.stream(splits).filter(StringUtils::isNotBlank).collect(Collectors.joining(", "));
If you know how much elements the array has, a simple way is doing this:
String appendedString = "" + array[0] + "" + array[1] + "" + array[2] + "" + array[3];
I need to concatenate a variable number of arguments (type String) to one String:
E.g.:
System.out.println( add("ja", "va") );
should return java but my implementation returns jaja.
I tried this:
public static String add(String... strings) {
for (String arg : strings) {
return String.format(arg.concat(arg));
}
return "string";
}
What am I doing wrong?
Nowadays you might want to use:
String.join(separator, strings)
You're returning on the first iteration of the loop (return String.format ...) rather than at the end. What you should use here is a StringBuilder:
public static String add(String... strings) {
StringBuilder builder = new StringBuilder();
for (String arg : strings) {
builder.append(arg);
}
return builder.toString(); //Outputs the entire contents of the StringBuilder.
}
Use Java 8's StringJoiner in combination with the stream API:
String joined = Stream.of(strings).collect(Collectors.joining());
Wrapped in a method, it could look like this:
import java.util.stream.Collectors;
import java.util.stream.Stream;
public static String join(String separator, String... strings) {
return Stream.of(strings).collect(Collectors.joining(separator));
}
There's plenty of ways, but a StringBuilder is probably the most efficient:
public static String add(String... strings) {
StringBuilder sb = new StringBuilder();
for (String arg : strings) {
sb.append(arg);
}
return sb.toString();
}
Basically, you initialise the builder as empty then loop through the arguments appending each one and finally return the contents of the builder.
You probably want to add some code in the loop to handle null values in the arguments (the array won't be null, but strings within it could be. As-is this method would append the string "null" for null values, which may not be what you want.
Try this:
String result;
for (int i =0, i < strings.size(), i++){
result += strings[i];
}
return result;
You could use the new Java 8 lambdas and something like,
String[] arr = { "ja", "va" };
Optional<String> result = Arrays.asList(arr).parallelStream()
.reduce(new BinaryOperator<String>() {
public String apply(String t, String u) {
return t + u;
}
});
System.out.println(result.get());
To answer your question, this line is what you are doing wrong:
return String.format(arg.concat(arg));
The first time in the for each loop arg would be the string ja. You take that string and concatenat with the same var arg which is ja. Then you return, so you never get into your second run of the loop.
To fix, do what others suggested and use something to collect and join for each variable.
To give you another solution to join, you can try to just join the varargs varible. So you can try:
return String.join ('',strings);
This way, no loop to write, just join the strings. This assumes Java 9.
This question is from an assignment. I have to override a toString() method in a class that creates a circularly linked list and I actually have a toString() method that works great, it passes all of my tests everything. So my project is autograded and it apparently doesn't approve of my method 100%. So my question is: is there a better way to write this toString() method that would be more efficient?
public String toString()
{
if (size == 0)
{
return "[]";
}
else
{
String output = "";
Node<E> tempNode = actualElement;
while (tempNode.next() != actualElement)
{
if (output.equals(""))
{
output = "[" + output + tempNode.data().toString();
tempNode = tempNode.next();
}
else
{
output = output + ", " + tempNode.data().toString();
tempNode = tempNode.next();
}
}
output = output + ", " + tempNode.data().toString() + "]";
return output;
}
If i need to elaborate more on the class structure so that this makes more sense let me know.
Use StringBuilder.
StringBuilder builder = new StringBuilder();
builder.append("some text");
builder.append("more text");
return builder.toString();
To improve it further, you can use StringBuilder and append each computed String literals. This saves JVM creating load of individual String literals and thus improves performance.
Strings should always be used unless string builders offer an advantage in terms of simpler code or better performance
if you need to concatenate a large number of strings, appending to a StringBuilder object is more efficient.
I assume actualElement is defined elsewhere in the class, though a better name might be nice. The if (output.equals("")) is unnecessary. Just start the output StringBuilder with a [, and just append to it.
However, you are depending on your list actually being circular. If this list ends up not looping around, you will get an NPE. And, if the list looks more like a 6, as in [A, B, C, D, E, C, D, E...], then the loop will never end.
Use StringBuilder instead may do your a favor.This is snippet is copied from AbstractCollection.toString(),take a look at it.
public String toString() {
Iterator<E> i = iterator();
if (! i.hasNext())
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
E e = i.next();
sb.append(e == this ? "(this Collection)" : e);
if (! i.hasNext())
return sb.append(']').toString();
sb.append(", ");
}
}
First you should use a StringBuilder for concatenation of your Strings.
take a look here:
http://javarevisited.blogspot.co.at/2011/07/string-vs-stringbuffer-vs-stringbuilder.html
StringBuilder sb = new StringBuidler();
Node<E> tempNode = actualElement;
while (tempNode.next() != actualElement)
{
if (sb.length() == 0)
{
sb.append("[").append(tempNode.data().toString());
}
else
{
sb.append(", ").append(tempNode.data().toString());
}
tempNode = tempNode.next();
}
sb.append(", ").append(tempNode.data().toString()).append("]");
return sb.toString();
This question already has answers here:
Java: convert List<String> to a join()d String
(23 answers)
Closed 6 years ago.
What is the best way to concatenate a list of String objects? I am thinking of doing this way:
List<String> sList = new ArrayList<String>();
// add elements
if (sList != null)
{
String listString = sList.toString();
listString = listString.subString(1, listString.length() - 1);
}
I somehow found this to be neater than using the StringBuilder/StringBuffer approach.
Any thoughts/comments?
Use one of the the StringUtils.join methods in Apache Commons Lang.
import org.apache.commons.lang3.StringUtils;
String result = StringUtils.join(list, ", ");
If you are fortunate enough to be using Java 8, then it's even easier...just use String.join
String result = String.join(", ", list);
Using Java 8+
String str = list.stream().collect(Collectors.joining())
or even
String str = String.join("", list);
Your approach is dependent on Java's ArrayList#toString() implementation.
While the implementation is documented in the Java API and very unlikely to change, there's a chance it could. It's far more reliable to implement this yourself (loops, StringBuilders, recursion whatever you like better).
Sure this approach may seem "neater" or more "too sweet" or "money" but it is, in my opinion, a worse approach.
A variation on codefin's answer
public static String concatStringsWSep(Iterable<String> strings, String separator) {
StringBuilder sb = new StringBuilder();
String sep = "";
for(String s: strings) {
sb.append(sep).append(s);
sep = separator;
}
return sb.toString();
}
If you are developing for Android, there is TextUtils.join provided by the SDK.
This is the most elegant and clean way I've found so far:
list.stream().collect(Collectors.joining(delimiter));
Guava is a pretty neat library from Google:
Joiner joiner = Joiner.on(", ");
joiner.join(sList);
Have you seen this Coding Horror blog entry?
The Sad Tragedy of Micro-Optimization Theater
I am not shure whether or not it is "neater", but from a performance-standpoint it probably won't matter much.
I prefer String.join(list) in Java 8
It seems to me that the StringBuilder will be quick and efficient.
The basic form would look something like this:
public static String concatStrings(List<String> strings)
{
StringBuilder sb = new StringBuilder();
for(String s: strings)
{
sb.append(s);
}
return sb.toString();
}
If that's too simplistic (and it probably is), you can use a similar approach and add a separator like this:
public static String concatStringsWSep(List<String> strings, String separator)
{
StringBuilder sb = new StringBuilder();
for(int i = 0; i < strings.size(); i++)
{
sb.append(strings.get(i));
if(i < strings.size() - 1)
sb.append(separator);
}
return sb.toString();
}
I agree with the others who have responded to this question when they say that you should not rely on the toString() method of Java's ArrayList.
ArrayList inherits its toString()-method from AbstractCollection, ie:
public String toString() {
Iterator<E> i = iterator();
if (! i.hasNext())
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
E e = i.next();
sb.append(e == this ? "(this Collection)" : e);
if (! i.hasNext())
return sb.append(']').toString();
sb.append(", ");
}
}
Building the string yourself will be far more efficient.
If you really want to aggregate the strings beforehand in some sort of List, you should provide your own method to efficiently join them, e.g. like this:
static String join(Collection<?> items, String sep) {
if(items.size() == 0)
return "";
String[] strings = new String[items.size()];
int length = sep.length() * (items.size() - 1);
int idx = 0;
for(Object item : items) {
String str = item.toString();
strings[idx++] = str;
length += str.length();
}
char[] chars = new char[length];
int pos = 0;
for(String str : strings) {
str.getChars(0, str.length(), chars, pos);
pos += str.length();
if(pos < length) {
sep.getChars(0, sep.length(), chars, pos);
pos += sep.length();
}
}
return new String(chars);
}
I somehow found this to be neater than
using the StringBuilder/StringBuffer
approach.
I guess it depends on what approach you took.
The AbstractCollection#toString() method simply iterates over all the elements and appends them to a StringBuilder. So your method may be saving a few lines of code but at the cost of extra String manipulation. Whether that tradeoff is a good one is up to you.
Rather than depending on ArrayList.toString() implementation, you could write a one-liner, if you are using java 8:
String result = sList.stream()
.reduce("", String::concat);
If you prefer using StringBuffer instead of String since String::concat has a runtime of O(n^2), you could convert every String to StringBuffer first.
StringBuffer result = sList.stream()
.map(StringBuffer::new)
.reduce(new StringBuffer(""), StringBuffer::append);
Next variation on Peter Lawrey's answer without initialization of a new string every loop turn
String concatList(List<String> sList, String separator)
{
Iterator<String> iter = sList.iterator();
StringBuilder sb = new StringBuilder();
while (iter.hasNext())
{
sb.append(iter.next()).append( iter.hasNext() ? separator : "");
}
return sb.toString();
}
Assuming it's faster to just move a pointer / set a byte to null (or however Java implements StringBuilder#setLength), rather than check a condition each time through the loop to see when to append the delimiter, you could use this method:
public static String Intersperse (Collection<?> collection, String delimiter)
{
StringBuilder sb = new StringBuilder ();
for (Object item : collection)
{
if (item == null) continue;
sb.append (item).append (delimiter);
}
sb.setLength (sb.length () - delimiter.length ());
return sb.toString ();
}
In java 8 you can also use a reducer, something like:
public static String join(List<String> strings, String joinStr) {
return strings.stream().reduce("", (prev, cur) -> prev += (cur + joinStr));
}
Depending on the need for performance and amount of elements to be added, this might be an ok solution. If the amount of elements are high, the Arraylists reallocation of memory might be a bit slower than StringBuilder.
Using the Functional Java library, import these:
import static fj.pre.Monoid.stringMonoid;
import static fj.data.List.list;
import fj.data.List;
... then you can do this:
List<String> ss = list("foo", "bar", "baz");
String s = stringMonoid.join(ss, ", ");
Or, the generic way, if you don't have a list of Strings:
public static <A> String showList(List<A> l, Show<A> s) {
return stringMonoid.join(l.map(s.showS_()), ", ");
}
if you have json in your dependencies.you can use new JSONArray(list).toString()