Obtaining all repeated characters' position in a string using Java Stream API
You do not need encodeString and you do not even need a Pair class. You only use this method to build a list of each index with the character of the string at that index. Instead, you can directly use an IntStream that will go over the indexes of each character of the String.

Map&lt;Character, List&lt;Integer&gt;&gt; map =
    IntStream.range(0, str.length())
             .boxed()
             .collect(Collectors.groupingBy(str::charAt, HashMap::new, Collectors.toList()));


This creates an IntStream going from 0 to the length of the String (excluded). We turn this primitive Stream into a Stream&lt;Integer&gt; using boxed: we will need to box each index to store them in a list anyway, and having a Stream of objects enable us to use the built-in groupingBy(classifier, mapFactory, downstream) collector.

This collector groups each element of the Stream by the classifier given. In this case, the classifier is a function returning the character at the index considered. It is using the method-reference str::charAt (which would be equivalent to the lambda expression i -&gt; str.charAt(i)). The downstream collector is used to collect all elements that are classified to the same key; in this case, it is simply toList() which will collect the indexes into a list. By default, groupingBy isn't specified to return a specific Map implementation (the current Oracle JDK returns a HashMap but that cannot be relied upon). Since we're going to post-process that map, giving HashMap::new as the map supplier makes sure that we end up with a HashMap.

The Stream API doesn't offer a way to do a GROUP BY HAVING, like we would like here (in SQL jargon), so 2 passes are needed. The second one can be simplified though: instead of creating a new Stream pipeline, we can use

map.values().removeIf(l -&gt; l.size() &lt;= 1);


to remove every entry from the map where the value is a list that has a size less than 1. This works because values() returns a view of the map, so changes to it reflect through the map. And then removeIf gives us the ability to remove the elements matching the given predicate.

So all in all, you can have:

public static Map&lt;Character,List&lt;Integer&gt;&gt; charMaps(String str) {
    Map&lt;Character, List&lt;Integer&gt;&gt; map =
        IntStream.range(0, str.length())
                 .boxed()
                 .collect(Collectors.groupingBy(str::charAt, HashMap::new, Collectors.toList()));
    map.values().removeIf(l -&gt; l.size() &lt;= 1);
    return map;
}