On Sat, 19 Sep 2026 10:05:35 GMT, Tagir F. Valeev <[email protected]> wrote:
>> Three options were suggested about the new API: >> - ListFormat.formatting() >> - ListFormat.toCollector() >> - Collectors.listFormatting(ListFormat) static method >> I feel it should belong to ListFormat, but I'm open to discussions. >> >> For testing, I tested a couple of scenarios and a few corner cases (empty >> stream, null element, parallel stream) in a simple non-parameterized JUnit >> test. I believe that it's enough, given that the implementation is trivial, >> and ListFormat itself, as well as Stream API is already thoroughly tested by >> other tests. Tell me if you feel that some testing scenarios are missing, >> I'll happily add them. >> >> --------- >> - [x] I confirm that I make this contribution in accordance with the >> [OpenJDK Interim AI Policy](https://openjdk.org/legal/ai). > > Tagir F. Valeev has updated the pull request incrementally with one > additional commit since the last revision: > > 8391789: Dumb error fix A quick note on use cases. I can provide use cases from our codebase (IntelliJ IDEA) where the collector was involved. We used `ListFormat` from icu4j to join lists and streams for years, and recently switched to JDK implementation. In our case, we still need separate methods because a globally known current `Locale` should be substituted automatically (it differs from `Locale.getDefault()` and depends on which language pack is activated by the user). As I said before, we limit ourselves to three formats: wide-and, wide-or and narrow-and. 1. Wide-and -- formatting of an error message in Javadoc snippets: JavaBundle.message( "javadoc.snippet.error.unknown.enum.value", tagName, attribute.key(), attribute.value(), Stream.of(enumClass.getEnumConstants()).map(val -> "'" + val.name().toLowerCase(Locale.ROOT) + "'") .collect(NlsMessages.joiningAnd())))) // in resources: javadoc.snippet.error.unknown.enum.value=@{0}: unknown {1} ''{2}''; only {3} are supported Possible result (from test-data): @link: unknown type 'none'; only 'link' and 'linkplain' are supported @highlight: unknown type 'underlined'; only 'bold', 'italic', and 'highlighted' are supported The code is somewhat overly generic; it is parameterized by enumClass, which is either `public enum HighlightType {BOLD, ITALIC, HIGHLIGHTED}` or `public enum LinkType {LINK, LINKPLAIN}`, no other options right now. 2. Wide-and -- formatting inspection message that suggests adding more steps to the existing Stream API call: String fusedSteps = newTerminal.fusedElements().collect(NlsMessages.joiningAnd()); JavaBundle.message("inspection.fuse.stream.operations.fix.name", fusedSteps); // in resources: inspection.fuse.stream.operations.fix.name=Fuse {0} into the Stream API chain Possible result: Fuse ArrayList, 'sort', and 'toArray' into the Stream API chain Fuse 'sort' into the Stream API chain Fuse HashSet and ArrayList into the Stream API chain 3. Wide-and -- formatting inspection message reporting unreachable catch messages: String types = caughtCopy.stream().map(JavaHighlightUtil::formatType).collect(NlsMessages.joiningAnd()); String message = JavaAnalysisBundle.message("inspection.unreachable.catch.message", types, caughtCopy.size()); // in resources: inspection.unreachable.catch.message=Unreachable section: {1, choice, 0#exception|2#exceptions} ''{0}'' {1, choice, 0#has|2#have} already been caught Possible result: Unreachable section: exception 'java.io.FileNotFoundException' has already been caught Unreachable section: exceptions 'C.E1' and 'C.E2' have already been caught 4. Wide-or -- intention action description that suggests converting a number to various other formats: String options = chooser.actions().stream().map(ModCommandAction::getFamilyName).collect(NlsMessages.joiningOr()); LangBundle.message("intention.name.convert.number.to.with.text.preview", options) // in resources: intention.name.convert.number.to.with.text.preview=Convert number to {0} Possible result: Convert number to hex, binary, or octal List of choices may differ based on the input number, its type and Java version used (e.g., no 'binary' option on Java 6). 5. Wide-or -- data-flow analysis information which shows statically known possible values of a variable: values.stream().map(DfaPsiUtil::renderValue).sorted().collect(NlsMessages.joiningOr()) For example, if you have the code like this: void test(String str) { if (str.equals("hello") || str.equals("world")) { System.out.println(str); } } And you press Ctrl+Shift+P twice on 'str' inside 'if', you'll see `Value: "hello" or "world"` 6. Narrow-and -- 'Build modules' menu item in the popup menu: String moduleNames = Stream.of(modules).map(m -> "'"+m.getName()+"'").collect(NlsMessages.joiningNarrowAnd()); presentationText = moduleNames.length() > 20 ? JavaCompilerBundle.message("action.make.selected.modules.text") : JavaCompilerBundle.message("action.make.few.modules.text", moduleNames); // in resources: action.make.selected.modules.text=Build Selected _Modules action.make.few.modules.text=Build _Modules {0} A single module case is handled separately. Here, we prefer to keep the list narrow because the horizontal space in the popup menu item is kinda limited. Still, it's better to use localized joining over simply `joining(", ")`, because we want it to look nicely, e.g., in Japanese locale (using "、" instead of ", "). ------------- PR Comment: https://git.openjdk.org/jdk/pull/32716#issuecomment-5777500479
