Print Hollow Square in Java
Problem
A hollow square only needs stars on its border — the first row, the last row, and the first and last position of every row in between — with every other position left blank.
Given a size n, print an n by n square where only the border is stars and the interior is blank.
Java Program
public class HollowSquare {
public static void main(String[] args) {
int n = 5;
for (int i = 0; i < n; i++) {
StringBuilder row = new StringBuilder();
for (int j = 0; j < n; j++) {
if (row.length() > 0) row.append(" ");
boolean border = (i == 0 || i == n - 1 || j == 0 || j == n - 1); // true only on the outer edge
row.append(border ? "*" : " ");
}
System.out.println(row);
}
}
}Output
Core Logic
Visiting every position in the grid, just like the solid square, but only printing a star at the border positions and a blank everywhere else, hollows out the interior.
- 1A position is on the border when its row is the first or last row, or its column is the first or last column —
i == 0 || i == n - 1 || j == 0 || j == n - 1. - 2Every position in the grid is still visited, unlike a hollow triangle where the interior skip depends on the row shape.
- 3Border positions print
"*"; every other position prints a single space, keeping every row the same printed width. - 4The same space-separator convention used by the solid square keeps the columns visually aligned.
n = 5, row 0 and row 4 are entirely stars, while rows 1 through 3 only have stars in their first and last column.Key Point: The interior positions still have to print a blank character, not be skipped — omitting them instead of printing a space would collapse the row's width and break the square's alignment.
Why: The nested loop still visits all n² positions to decide star-versus-blank, even though most interior positions print nothing but a space.
Key Concepts
Approach 2: Java 8
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class HollowSquareStream {
public static void main(String[] args) {
int n = 5;
IntStream.range(0, n)
.mapToObj(i -> IntStream.range(0, n)
.mapToObj(j -> (i == 0 || i == n - 1 || j == 0 || j == n - 1) ? "*" : " ")
.collect(Collectors.joining(" ")))
.forEach(System.out::println);
}
}
Output
Core Logic
Since every position's border-or-interior status depends only on its own row and column, mapping each column index directly to a star or a space reproduces the outline without visiting neighboring cells.
- 1
IntStream.range(0, n)generates one stream element per rowi. - 2For each row, an inner
IntStream.range(0, n)generates that row's column indicesj. - 3
.mapToObj(j -> (i == 0 || i == n - 1 || j == 0 || j == n - 1) ? "*" : " ")tests the same border condition the loop version does, per position. - 4
Collectors.joining(" ")joins that row's characters beforeforEachprints it.
j = 0 and j = 4 satisfy the border condition, so the joined row is a star, three blank positions, and a closing star.Key Point: A per-cell conditional formula like this maps onto a stream just as cleanly as a per-cell numeric one — the border test reads its own i and j only, with no dependency on any other cell's result.
Why: The nested streams still evaluate the border condition once per grid position, a total proportional to n², without collecting the full square.