Writing a for loop to build a String using Streams
One issue is that you cannot consume a stream with index. You can more or less have the same result with a IntStream bounded to your list's size.

Then you just have map each int to a code with the same logic. And, finally, collect them (This is the only part where the Stream will shine).

String string = IntStream.range(0, codes.size())
            .mapToObj(i -&gt; {
                String code = codes.get(i);
                code = "example".equals(code) ? "EX":code.toUpperCase();
                return String.format("%1$d~%2$s", i, code);
            })
            .collect(Collectors.joining("|"));