Monday, 7 April 2025

๐ŸŽฏ Tricky Java 8 map() vs flatMap() Questions

๐Ÿ”ฅ Q1: What's the output of this?


List<String> words = Arrays.asList("Java", "Spring"); List<String> result = words.stream() .map(word -> word.split("")) .flatMap(Arrays::stream) .distinct() .collect(Collectors.toList()); System.out.println(result);

โœ… Answer:

Output:


[J, a, v, S, p, r, i, n, g]
  • word.split("") โ†’ gives String[]

  • map() gives Stream<String[]>

  • flatMap(Arrays::stream) flattens Stream<String[]> โ†’ Stream<String>

  • distinct() removes duplicates

๐Ÿ”ฅ Trick: map(Arrays::stream) would give you Stream<Stream<String>> and fail to compile in .collect().



๐Ÿ”ฅ Q2: Why does this not compile?


List<List<Integer>> list = Arrays.asList( Arrays.asList(1, 2), Arrays.asList(3, 4) ); List<Stream<Integer>> result = list.stream() .map(l -> l.stream()) .collect(Collectors.toList());

โœ… Answer:

It compiles, but the result is List<Stream<Integer>>, not List<Integer>.

To flatten the list, use:


List<Integer> result = list.stream() .flatMap(List::stream) .collect(Collectors.toList());

๐Ÿ‘‰ Trick: flatMap is needed to flatten nested streams.


๐Ÿ”ฅ Q3: How is flatMap() different from map() in Optional?


Optional<String> name = Optional.of("Java"); Optional<Optional<String>> result = name.map(n -> Optional.of(n.toUpperCase())); Optional<String> flat = name.flatMap(n -> Optional.of(n.toUpperCase()));

โœ… Answer:

  • map() โ†’ wraps result โ†’ Optional<Optional<String>>

  • flatMap() โ†’ avoids wrapping โ†’ Optional<String>

๐Ÿง  Trick: Use flatMap when the function already returns an Optional.


๐Ÿ”ฅ Q4: What happens here?


Stream<String> stream = Stream.of("apple", "banana"); stream.map(s -> s.toUpperCase()); stream.forEach(System.out::println);

โœ… Answer:

๐Ÿ’ฅ Runtime Exception: IllegalStateException: stream has already been operated upon or closed

Why? Because map() doesnโ€™t mutate the original stream โ€” it returns a new one. But it was never assigned.

๐Ÿง  Trick: Streams are one-time use. Always assign or chain after map() or flatMap().


๐Ÿ”ฅ Q5: Can you convert a List<String> where each string is comma-separated into a List<String> of all elements?

โœ… Answer:

Yes, with flatMap():


List<String> input = Arrays.asList("a,b,c", "d,e"); List<String> result = input.stream() .map(s -> s.split(",")) .flatMap(Arrays::stream) .collect(Collectors.toList());

Output:


[a, b, c, d, e]

๐Ÿ’ก Trick: split() gives arrays. Need flatMap(Arrays::stream) to flatten.


๐Ÿ”ฅ Q6: Whatโ€™s the output?


List<String> list = Arrays.asList("a,b", "c,d", "e"); List<String[]> mapped = list.stream() .map(s -> s.split(",")) .collect(Collectors.toList()); System.out.println(mapped.size()); // ? System.out.println(mapped.get(0)[0]); // ?

โœ… Answer:

  • mapped.size() โ†’ 3

  • mapped.get(0)[0] โ†’ "a"

๐Ÿง  Trick: map() does not flatten โ€” you still have a List<String[]>, not a flat List<String>. Only flatMap() can do that.


๐Ÿ”ฅ Q7: What does this do?


Stream<String> stream = Stream.of("java", "spring"); Stream<Stream<Character>> result = stream.map(str -> str.chars().mapToObj(c -> (char) c) );

โœ… Answer:

  • It creates a Stream<Stream<Character>>

  • Each inner stream represents characters of a string

โœ… If you want a flat Stream<Character>:


Stream<Character> flat = stream .flatMap(str -> str.chars().mapToObj(c -> (char) c));

๐Ÿ”ฅ Trick: Interviewers love chars + streams + mapping โ†’ always pay attention to return types.


๐Ÿ”ฅ Q8: Can you use flatMap() with primitives?

โœ… Answer:

Yes, but carefully! Primitives like IntStream, LongStream etc. don't work directly with flatMap.

Example:


List<String> list = Arrays.asList("1,2", "3,4"); List<Integer> result = list.stream() .map(s -> s.split(",")) .flatMap(Arrays::stream) .map(Integer::parseInt) .collect(Collectors.toList());

๐Ÿ”ฅ Trick: To flatMap a primitive stream, use:


.flatMapToInt(str -> str.chars()) // returns IntStream

๐Ÿ”ฅ Q9: Which is more efficient: map().flatMap() vs flatMap() directly?

โœ… Answer:

  • If you're nesting transformations (e.g. map().map()), it's fine.

  • But if you're mapping and flattening, flatMap() is better.

Bad:


.stream() .map(x -> someMethodReturningStream(x)) .map(stream -> stream.collect(Collectors.toList())) // Oops!

Better:


.stream() .flatMap(this::someMethodReturningStream)

๐Ÿ”ฅ Trick: .flatMap() avoids intermediate structures (like List of Lists) โ€” better for performance and memory.


๐Ÿ”ฅ Q10: What if flatMap returns null?


Stream.of("hello", "world") .flatMap(s -> null) // What happens here? .collect(Collectors.toList());

โœ… Answer:

๐Ÿ’ฅ NullPointerException

โŒ You cannot return null from a flatMap โ€” it must return a valid Stream. If you want an empty result, return Stream.empty().

Correct way:


.flatMap(s -> Stream.empty())

๐Ÿ”ฅ Trick: Always return a Stream, even if itโ€™s empty. No null allowed in flatMap().


๐Ÿงช Final Trick:

"Use map() when you transform values. Use flatMap() when you're dealing with nested structures (like lists of lists or Optionals of Optionals)."

No comments:

Post a Comment