The lists for all keys belonging to the same group are identical, so you can save work by collecting only one list for each group before mapping them to the original A
values.
Using the Stream API, a solution may look like
List<Foo> list = Arrays.asList(new Foo("FM11","1"), new Foo("FM1122","2"));
Map<String,List<String>> groups = list.stream()
.collect(Collectors.groupingBy(foo -> foo.getA().substring(0, 4),
Collectors.mapping(Foo::getB, Collectors.toList())));
Map<String,List<String>> result = list.stream()
.collect(Collectors.toMap(Foo::getA, foo -> groups.get(foo.getA().substring(0, 4))));
result.forEach((k,v) -> System.out.println(k+" -> "+v));
FM1122 -> [1, 2]
FM11 -> [1, 2]
You can do it even more efficiently when not using the Stream API. With a loop, we can do both operations in one go, halving the work of looking up the groups in the map.
Map<String,List<String>> groups = new HashMap<>(), result = new HashMap<>();
for(Foo foo: list) {
List<String> bList
= groups.computeIfAbsent(foo.getA().substring(0, 4), x -> new ArrayList<>());
bList.add(foo.getB());
result.put(foo.getA(), bList);
}
The result is identical.