2
\$\begingroup\$

This should be really simple. I'm searching for the cleanest & shortest way to add a newline to a non-null String if it is not empty, i.e. myString.isEmpty() is true. I know of a number of ways to do this, but none of them are as elegant as I would like them to.

For context, the string I'm working on will essentially be a list of key-value pairs that is filled with a loop. Every key-value-pair needs to have a newline appended after it, though not if it is the last one. An example for the end value of myString might be the following:

Boss : Julia
Worker : Louis
Intern : Tom

I could do

myString += myString.isEmpty() ? "" : "\n";

but is this really the best way to do this?

I also thought of

if(!myString.isEmpty()) myString += "\n";

Which way would be preferable, and why? Are there better alternatives?

\$\endgroup\$
  • \$\begingroup\$ Try Apache StringUtils.defaultIfBlank. This may not be the most efficient approach and it requires another library but it is very clear from the code what is being done. \$\endgroup\$ – Freiheit Jun 17 '15 at 17:29
5
\$\begingroup\$

Every key-value-pair needs to have a newline appended after it, though not if it is the last one.

So are you interested to know how to concatenate Strings together using \n as a delimiter, or are you still interested to know how can you append \n to a non-empty String? Both have different implementations...

(using Java 8 where applicable below)

\n as a delimiter:

String toString = organizationMap.entrySet().stream()
                    .map(ThisClass::constructStringFromEntry)
                    .filter(v -> !v.isEmpty())
                    .collect(Collectors.joining("\n"));

\n as an optional suffix:

StringBuilder builder = new StringBuilder();
Iterator<Entry<String, String>> iterator = organizationMap.entrySet().iterator();
while (iterator.hasNext()) {
    Entry<String, String> entry = iterator.next();
    // some other processing...
    // time to append the current entry to builder
    String entryString = constructStringFromEntry(entry);
    builder.append(entryString);
    if (!entryString.isEmpty() && iterator.hasNext()) {
        builder.append('\n');
    }
}
String toString = builder.toString();

I am suggesting the usage of a StringBuilder here since the kind of String concatenation in a loop is usually structured, hence it can be better done relying on that rather than +. Usually, I will prefer the enhanced for-loop over using an explicit Iterator, but its usage here is required in order to avoid adding the last \n.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ I'm interested in both of these, but simply concatenating the strings with streams seems more elegant than the solution I currently have. Thank you! \$\endgroup\$ – Luke35 Jun 17 '15 at 10:55
3
\$\begingroup\$

I fear there isn't much to improve. You could avoid the concatenation if the String is empty :

myString = myString.isEmpty() ? myString : myString + '\n';
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ The problem I see with this solution is having to write myString four times - which is OK for myString, but not that nice-looking for reallyReallyReallyComplicatedAndLongStringName. Performance-wise, this would of course be better, but performance should not be an issue here. Thank you nontheless! \$\endgroup\$ – Luke35 Jun 17 '15 at 10:43
  • \$\begingroup\$ Put the line in a method. Then you only have to write reallyReallyReallyComplicatedAndLongStringName once. \$\endgroup\$ – Gilbert Le Blanc Jun 18 '15 at 21:14
2
\$\begingroup\$

From the performance points of view, it would be better to use second sample. Cause of in the first sample JVM creates two String objects for "" and "\n" (it depends on compiler also) and make two operation of concatination in the both cases.

Would be better to use StringBuilder or StringBuffer instead String object, cause of "+" will create new String object from myString and "\n" through StringBuffer.append() and in append method you cat put char or byte primitives instead of String object.

if (stringBuilder.length() == 0) stringBuilder.append('\n');
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Since Java 6, unless particular cases (in loops for instance), using a StringBuilder should not change a lot since the compiler transforms automatically strings concatenations into StringBuilder calls. Eg: String one = "1"; String two = "2"; String three = one + two; into String three = new StringBuilder().append(one).append(two).toString();. \$\endgroup\$ – Alban Dericbourg Jun 17 '15 at 11:25
  • \$\begingroup\$ You are right, but in our case it will be translates to someone like this. myString = new StringBuilder().append(myString).append(myString.isEmpty() ? new String("") : new String("\n")).toString(); it will allocate two new String object and create default length arrays and for the StringBuilder also and adds some operations for GC. \$\endgroup\$ – swepss Jun 17 '15 at 11:41
  • \$\begingroup\$ @Luke35 (Sorry, I can't add comments to non-my answers) from the Java Code Convention and readable sources it would be better to use if construction. if (builder.lenght() == 0) { builder.append('\n'); } \$\endgroup\$ – swepss Jun 17 '15 at 11:44
0
\$\begingroup\$

This is a common pattern - only apply the separator if both parts are substantial.

public static String join(String a, String j, String b) {
    if (a == null) {
        // No a - just becomes b.
        return b;
    }
    if (b == null) {
        // No b - just becomes a.
        return a;
    }
    if (a.length() == 0) {
        // No a - just becomes b.
        return b;
    }
    if (b.length() == 0) {
        // No b - just becomes a.
        return a;
    }
    return a + j + b;
}

public void test() {
    System.out.println(join(null, ",", "Hello"));
    System.out.println(join("Hello", ",", "Hello"));
    String s = "";
    for (String append : new String[]{"Hello", "a", "", "", null, "", "b"}) {
        s = join(s, ",", append);
    }
    System.out.println(s);
}

Attempting to do a complicated thing with a one-liner is doomed.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.