Java ProgramsPatternsPrint X Pattern

Print X Pattern in Java

intermediate·  Patterns  ·  Star Patterns

Problem

The letter X is traced by a square grid's two diagonals at once — the main diagonal running top-left to bottom-right, and the anti-diagonal running top-right to bottom-left.

Given a grid size n, print an X shape made of stars where the two diagonals of the grid meet.

Input
5
Output
* * * * * * * * *

Java Program

Java
public class XPattern { public static void main(String[] args) { int n = 5; for (int row = 0; row < n; row++) { StringBuilder line = new StringBuilder(); for (int col = 0; col < n; col++) { if (col == row || col == n - 1 - row) { // on the main diagonal or the anti-diagonal line.append('*'); } else { line.append(' '); } } System.out.println(line); } } }

Output

* * * * * * * * *

Core Logic

Checking whether each grid position sits on either diagonal, and printing a star only there, traces both diagonal lines in a single sweep of the grid.

How It Works
  1. 1col == row tests whether a position lies on the main diagonal, running from the top-left corner down to the bottom-right.
  2. 2col == n - 1 - row tests the anti-diagonal instead, running from the top-right corner down to the bottom-left.
  3. 3A star is printed if either condition holds; every other position prints a space.
  4. 4Both loops run 0 to n - 1, visiting every cell of the square grid exactly once.
In the middle row (row = 2 for n = 5), both diagonal conditions point to the same column, col = 2 — that's why the X pinches to a single star there.
💡

Key Point: The two diagonal checks only agree at the grid's exact center when n is odd — that's what makes the shape cross cleanly rather than leaving a gap in the middle.

Complexity
Time Complexity: O(n²)Space Complexity: O(1)

Why: The nested loop evaluates the diagonal conditions once per grid cell, a total proportional to n², with no storage beyond the loop counters and a per-row StringBuilder.

Key Concepts

nested for loopdiagonal condition2D grid

Approach 2: Java 8

Java
import java.util.stream.Collectors; import java.util.stream.IntStream; public class XPatternStream { public static void main(String[] args) { int n = 5; IntStream.range(0, n) .mapToObj(row -> IntStream.range(0, n) .mapToObj(col -> (col == row || col == n - 1 - row) ? "*" : " ") .collect(Collectors.joining(""))) .forEach(System.out::println); } }

Output

* * * * * * * * *

Core Logic

Since each position's on-diagonal status depends only on its own row and column, mapping every column index directly to that test traces both diagonals without visiting neighboring cells.

How It Works
  1. 1IntStream.range(0, n) generates one stream element per row.
  2. 2For each row, an inner IntStream.range(0, n) generates that row's column indices.
  3. 3.mapToObj(col -> (col == row || col == n - 1 - row) ? "*" : " ") tests the same main-diagonal and anti-diagonal conditions the loop version does, per position.
  4. 4Collectors.joining("") concatenates that row's characters with no separator, matching the loop version's plain character append.
In the middle row (row = 2 for n = 5), both diagonal conditions point to column 2, so only that one position in the row maps to "*".
💡

Key Point: Each diagonal test reads only its own row and col, so it maps onto a stream exactly as cleanly as it fits inside a nested loop — no dependency on any other cell's result.

Complexity
Time Complexity: O(n²)Space Complexity: O(1)

Why: The nested streams still evaluate the diagonal conditions once per grid cell, a total proportional to n², without collecting the full grid.

Key Concepts

StreamIntStream.range()Collectors.joining()

Related Programs