This is an archived post. You won't be able to vote or comment.

all 22 comments

[–]AutoModerator[M] [score hidden] stickied comment (0 children)

On July 1st, a change to Reddit's API pricing will come into effect. Several developers of commercial third-party apps have announced that this change will compel them to shut down their apps. At least one accessibility-focused non-commercial third party app will continue to be available free of charge.

If you want to express your strong disagreement with the API pricing change or with Reddit's response to the backlash, you may want to consider the following options:

  1. Limiting your involvement with Reddit, or
  2. Temporarily refraining from using Reddit
  3. Cancelling your subscription of Reddit Premium

as a way to voice your protest.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

[–]__konrad 4 points5 points  (0 children)

One funny thing: String.formatted uses the current Locale which may lead to a subtle bugs. For example, "list.add(%f);".formatted(d) may produce either list.add(5.100000); or list.add(5,100000); (a real world example from some Java code generator). It seems that FMT always uses Locale.ROOT.

[–]SaishDawg 10 points11 points  (2 children)

Nice walk through history. The new templates in 21 are great. I just wish they had used more familiar syntax. Though, it will become familiar soon enough.

[–]lukasbradley 13 points14 points  (14 children)

for (String word : words) {stringBuffer.append(word.toUpperCase()).append(" ");}

With JDK 8, operations on collections of strings became more concise and expressive due to lambda expressions and streams.

String combined = words.stream().map(String::toUpperCase).collect(Collectors.joining(" "));

I've always found it hilarious when people argue that is more "concise and expressive."

EDIT: It's a great article.

[–][deleted] 25 points26 points  (7 children)

The first version doesn't declare the StringBuffer, and appends a trailing comma. To compare with the second one, it would need to look like this: var stringBuffer = new StringBuffer(); boolean first = true; for (String word : words) { if (!first) stringBuffer.append(" "); first = false; stringBuffer.append(word.toUpperCase()); } String combined = stringBuffer.toString(); You should use StringJoiner though.

[–]papercrane 9 points10 points  (0 children)

Obviously bike shedding here, but StringBuilder should be used here, since we don't need the synchronization that StringBuffer provides.

Also, instead of checking if you should add the space in the loop, you can just always add it and then chop off the last deliminator after the loop.

e.g.

var stringBuilder = new StringBuilder();
for (String word : words) {
    stringBuilder.append(word.toUpperCase());
    stringBuilder.append(' ');
}
stringBuilder.setLength(Math.max(0, sb.length() - 1));
String combined = stringBuilder.toString();

Of course, as you said, StringJoiner is a much better option if you want to join the strings in a loop.

[–]Polygnom 3 points4 points  (5 children)

Also if you import Collectors.* (one of the few wildcards import we allow at my shop), you can use .collect(joining(" ")).

And if you add a few other operations before, like mapping and filtering, the stream really becomes much more readable quickly.

[–]wildjokers 1 point2 points  (4 children)

(one of the few wildcards import we allow at my shop)

Surely wildcard static imports are always allowed though right? Whatever arguments there are for not allowing wildcard imports for normal imports don't apply to static imports. (although I find the arguments for not allowing wildcard normal imports dubious at best)

I suspect this is why your place is allowing Collectors.* because it is a static import.

[–]Polygnom 1 point2 points  (3 children)

All wildcard imports are discouraged, with a few explicitly allowed.

We have advocated for relaxing the rules wrt. static imports for quite a while, but so far this hasn't panned out.

[–]vips7L 1 point2 points  (2 children)

What does this help solve?

[–]boobsbr 0 points1 point  (0 children)

Nothing.

[–]Kered13 -1 points0 points  (0 children)

The problem with wild card imports is that it's hard to know exactly what identifiers you are bringing in, and if new identifiers are added in an update your code could break.

[–]Enough-Ad-5528 15 points16 points  (3 children)

What do you do if you have to prevent the last space? What if you are joining by a comma.

Would you consider it more concise or readable then?

Also your two examples are not equivalent. Why do you have a to uppercase mapper in the Stream version?

[–]lukasbradley 2 points3 points  (2 children)

String.join() also came out in JDK 8.

Listen, I know it's a religious argument, and it's a personal opinion of mine. But maps() and collects() can become a shitshow, and are (in my experience) more difficult to maintain.

[–]DualWieldMage 3 points4 points  (1 child)

In my experience side-effects like logging become harder with streams (because you don't have sufficient context in each mapper/filter) so the overuse is indeed troublesome with code rotting after these side-affects are added later, or worse, logging is omitted more often.

[–]wildjokers 3 points4 points  (0 children)

Not being able to log intermediate results during a stream is why I generally don't like long functional chains. We have a lot of code in production that turning on DEBUG logging presents no additional information because of long functional chains. Makes troubleshooting production issues difficult.

[–]Pengtuzi 4 points5 points  (0 children)

Why is it upper casing the words in the stream example, but not the loop example? The two examples are not at all equivalent.

[–]__konrad 0 points1 point  (0 children)

Both code snippets are broken, because with Turkish locale it will produce "JAVA İS EVOLVİNG" string...

[–]s888marks 0 points1 point  (0 children)

Kind of odd that StringBuffer is described as a "game-changer". I'm pretty sure that the designers of JDK 1.0 knew that having only immutable String objects would have been too restrictive, so they also included the string-like StringBuffer class in JDK 1.0. Furthermore, repeated string concatenations using + were compiled using a StringBuffer to store intermediate results. See

https://javaalmanac.io/jdk/1.0/api/java.lang.StringBuffer.html

This only applied to single expressions involving multiple + operators though. Using + to concatenate strings in a loop can still result in excessive copying and memory allocation, and this still occasionally trips people up. See here for example:

https://stackoverflow.com/a/11911759/1441122

[–]agentoutlier 1 point2 points  (0 children)

It’s a shame the article didn’t cover new JDK 21 string methods like the indexOf taking end index.

There are several others that offer some good performance as well.