Why can't mapToInt be used with collect(toList())?

mapToInt produces an IntStream, which doesn't have collect method taking a single Collector argument.

Since the end result is a List<Integer>, you don't have to transform the Stream to an IntStream:

List<Integer> lengths = a.stream().map(String::length).collect(Collectors.toList());

Transforming the Stream to an IntStream would make sense if you want to collect the elements of the Stream to an primitive array:

int[] lengths = a.stream().mapToInt(String::length).toArray();

If you want to transform to an IntStream and still use the collect method, you can write the following (which is less recommended):

List<Integer> lengths = 
    a.stream()
     .mapToInt(String::length)
     .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);

After .mapToInt you got an IntStream.

The collect definition for this stream is:

<R> R collect(Supplier<R> supplier,
              ObjIntConsumer<R> accumulator,
              BiConsumer<R, R> combiner);

Hence you cannot simply do toList() here.