java
string-conversion
lists
programming
coding-tips

Best way to convert list to comma separated string in java

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Converting a list to a comma-separated string in Java is simple, but the best method depends on the element type and the amount of formatting you need. For a List<String>, String.join is usually the cleanest answer. For other element types or custom formatting rules, streams with Collectors.joining are usually better.

Use String.join for List<String>

If the list already contains strings, the simplest and clearest approach is String.join.

java
1import java.util.List;
2
3public class Main {
4    public static void main(String[] args) {
5        List<String> items = List.of("Apple", "Banana", "Cherry");
6        String result = String.join(", ", items);
7        System.out.println(result);
8    }
9}

This is concise, readable, and directly expresses the intent: join these strings with this delimiter.

Use Streams for Other Element Types

If the list contains integers, domain objects, or values that need custom formatting, use a stream and map each element to a string first.

java
1import java.util.List;
2import java.util.stream.Collectors;
3
4public class Main {
5    public static void main(String[] args) {
6        List<Integer> numbers = List.of(1, 2, 3, 4);
7
8        String result = numbers.stream()
9            .map(String::valueOf)
10            .collect(Collectors.joining(", "));
11
12        System.out.println(result);
13    }
14}

This is the most flexible option because the mapping step can do more than just toString.

Format Objects Explicitly

When working with objects, decide what textual representation you actually want instead of relying blindly on toString.

java
1import java.util.List;
2import java.util.stream.Collectors;
3
4class User {
5    private final String name;
6    private final int age;
7
8    User(String name, int age) {
9        this.name = name;
10        this.age = age;
11    }
12
13    public String getName() {
14        return name;
15    }
16}
17
18public class Main {
19    public static void main(String[] args) {
20        List<User> users = List.of(new User("Ana", 30), new User("Ben", 27));
21
22        String result = users.stream()
23            .map(User::getName)
24            .collect(Collectors.joining(", "));
25
26        System.out.println(result);
27    }
28}

This avoids accidental output such as class names or debugging strings that were never meant for users.

Handle null Values Deliberately

Neither String.join nor a naive mapping pipeline is pleasant if the list can contain null values. Decide on a policy: filter them out, replace them, or fail fast.

java
1import java.util.Arrays;
2import java.util.List;
3import java.util.Objects;
4import java.util.stream.Collectors;
5
6public class Main {
7    public static void main(String[] args) {
8        List<String> items = Arrays.asList("A", null, "C");
9
10        String result = items.stream()
11            .filter(Objects::nonNull)
12            .collect(Collectors.joining(", "));
13
14        System.out.println(result);
15    }
16}

If null is meaningful, map it explicitly to a placeholder instead of silently dropping it.

Why StringBuilder Is Still Useful Sometimes

Before Java 8, manual StringBuilder loops were common. They are still valid when you need very custom logic, but they are usually not the best default anymore.

java
1import java.util.List;
2
3public class Main {
4    public static void main(String[] args) {
5        List<String> items = List.of("Dog", "Cat", "Fox");
6        StringBuilder sb = new StringBuilder();
7
8        for (String item : items) {
9            if (sb.length() > 0) {
10                sb.append(", ");
11            }
12            sb.append(item);
13        }
14
15        System.out.println(sb);
16    }
17}

This is still fine in low-level formatting code, but it is noisier than the standard library alternatives for everyday use.

Readability Matters More Than Micro-Optimization

For ordinary application code, the difference between String.join and Collectors.joining is rarely about performance. It is mostly about clarity and input shape.

A useful rule is:

  • 'List<String>: prefer String.join'
  • other element types: prefer stream mapping plus Collectors.joining
  • unusual formatting control flow: use StringBuilder

That rule keeps most codebases consistent.

Common Pitfalls

A common mistake is calling toString on a list and expecting a CSV string. list.toString() includes square brackets and uses its own formatting.

Another mistake is relying on object toString when the output is user-facing. Map explicitly to the property you actually want.

It is also easy to ignore null handling until the first NullPointerException or malformed output appears in production.

Summary

  • Use String.join when you already have a List<String>.
  • Use streams plus Collectors.joining for numbers and custom objects.
  • Handle null values explicitly instead of hoping they never occur.
  • Use StringBuilder only when you need custom control flow that the join APIs do not express cleanly.
  • Prefer the clearest method for the actual element type in the list.

Course illustration
Course illustration

All Rights Reserved.