Back to Stream Practice: Collections & Numbers
Q4Question 4 of 11

Convert lowercase string to uppercase using streams

Key Concepts
  • chars().map(Character::toUpperCase).mapToObj(c -> String.valueOf((char) c)).collect(joining()) converts character by character
  • For a list of strings, names.stream().map(String::toUpperCase).toList() is the practical approach
  • In production, just use str.toUpperCase() -- the stream version is an interview exercise
  • chars() returns IntStream (char codes as ints), not Stream<Character>
  • Collectors.joining() concatenates stream elements into a single String
  • toUpperCase() is locale-sensitive; use toUpperCase(Locale.ROOT) for identifiers to avoid the Turkish-i problem

Definition

Use chars().map(Character::toUpperCase).mapToObj(c -> String.valueOf((char) c)).collect(joining()) for character-by-character conversion, or simply str.toUpperCase() in production.
  • str.chars() returns an IntStream of character code points, not a Stream.
  • map(Character::toUpperCase) converts each int code point to uppercase, returning another IntStream.
  • mapToObj(c -> String.valueOf((char) c)) boxes the int to a single-character String.
  • collect(Collectors.joining()) concatenates all single-character strings into the final result.
  • For a list of strings, list.stream().map(String::toUpperCase).toList() applies uppercase to each element.
  • In production, str.toUpperCase() is simpler and faster. The stream approach is typically asked to test knowledge of chars(), mapToObj, and joining.

At National Bank of India, customer names captured in mixed case must be normalized to uppercase for the KYC register. The stream approach processes each character individually through a pipeline, like a conveyor belt where each letter passes through an uppercase stamp. In reality, you would just stamp the entire name at once with toUpperCase().

Understanding the Concepts

How do you convert a string to uppercase using streams?

JAVA
package com.bank.util;

import java.util.List;
import java.util.stream.Collectors;

public class UppercaseStreamDemo {
    public static void main(String[] args) {
        String input = "neft transfer";

        // Character-by-character stream conversion
        String upper = input.chars()
            .map(Character::toUpperCase)
            .mapToObj(c -> String.valueOf((char) c))
            .collect(Collectors.joining());

        System.out.println(upper);
    }
}
TEXT
NEFT TRANSFER

How do you convert a list of strings to uppercase?

JAVA
List<String> names = List.of("rajesh", "priya", "amit");

List<String> upperNames = names.stream()
    .map(String::toUpperCase)
    .toList();

System.out.println(upperNames);  // [RAJESH, PRIYA, AMIT]

Why does chars() return IntStream?

Java's chars() method returns IntStream because characters are represented as int code points internally. There is no CharStream in Java. You must use mapToObj to convert back to objects.

JAVA
// chars() returns IntStream, not Stream<Character>
"abc".chars()                    // IntStream: [97, 98, 99]
    .mapToObj(c -> (char) c)     // Stream<Character>: ['a', 'b', 'c']
    .toList();

What is the practical approach?

In production code, use str.toUpperCase() directly. The stream approach exists to test your understanding of the chars-mapToObj-joining pipeline.

JAVA
// Production: just use toUpperCase()
String simple = "neft transfer".toUpperCase();  // NEFT TRANSFER

What about locale sensitivity?

JAVA
// WRONG for identifiers: locale-dependent
"i".toUpperCase();              // "I" in English, but dotted-I in Turkish locale

// CORRECT for identifiers: locale-independent
"i".toUpperCase(java.util.Locale.ROOT);  // always "I"

How is map different from mapToObj?

| Method | Input | Output | Use When |
|--------|-------|--------|----------|
| map on IntStream | int | int | Transforming code points (uppercase) |
| mapToObj on IntStream | int | Object | Converting to String or Character |
| map on Stream | T | R | Transforming objects |

What are common mistakes?

WRONG: Casting IntStream directly to Stream without mapToObj.

JAVA
// WRONG: cannot cast IntStream to Stream<Character>
// input.chars().map(c -> (char) c)  // still IntStream!

CORRECT: Use mapToObj to box.

JAVA
// CORRECT: mapToObj converts IntStream to Stream<Object>
input.chars().mapToObj(c -> (char) c);  // Stream<Character>

What should a senior engineer know?

DIAGRAM
- `String::toUpperCase` is a method reference equivalent to `s -> s.toUpperCase()`. It is an unbound instance method reference.
- The stream approach creates many intermediate String objects (one per character). For performance-critical code, use `StringBuilder` or `str.toUpperCase()` directly.
- `Character.toUpperCase(int codePoint)` handles supplementary Unicode characters correctly (code points above U+FFFF).

Visual Overview

DIAGRAM
  "neft transfer"
       │
       ▼
  chars()  →  IntStream [110, 101, 102, 116, ...]
       │
       ▼
  map(Character::toUpperCase)  →  IntStream [78, 69, 70, 84, ...]
       │
       ▼
  mapToObj(c -> String.valueOf((char) c))  →  Stream ["N","E","F","T",...]
       │
       ▼
  collect(joining())  →  "NEFT TRANSFER"

Key Takeaway

The stream approach for uppercase conversion is chars().map(Character::toUpperCase).mapToObj(c -> String.valueOf((char) c)).collect(joining()). In production, use str.toUpperCase() directly. The stream version is an interview exercise that tests your knowledge of chars() (returns IntStream, not Stream), mapToObj (boxes int to object), and Collectors.joining() (concatenates strings).

For a list of strings, names.stream().map(String::toUpperCase).toList() is the practical approach. The map operation produces a new list without modifying the source, which matters in banking where original records must stay intact for audit.

Remember one sentence: chars() returns IntStream, mapToObj boxes to objects, and joining concatenates, but in production just use toUpperCase().

---

Share
Use ← → arrow keys to navigate