ThreadLocalRandom offers methods making it more convenient than Random.
The char type has been legacy since Java 5, essentially broken since Java 2. As a 16-bit value, char is physically incapable of representing most characters. Instead, use code point integer numbers to represent individual characters.
The Character class offers static methods toUpperCase & toLowerCase. By the way, the class also offers toTitleCase; see Difference between uppercase and titlecase.
The word “matrix” is the singular of “matrices”, in English.
Putting that all together, we get code that looks like the following.
final int origin = Character.codePointAt( "a" , 0 );
final int bound = origin + 26; // Twenty-six characters in US English alphabet, in US-ASCII subset of Unicode.
final int rows = 7, columns = 7;
final String[][] matrix = new String[ rows ][ columns ];
for ( int i = 0 ; i < matrix.length ; i++ )
{
for ( int j = 0 ; j < matrix.length - i ; j++ )
{
int codePoint = ThreadLocalRandom.current().nextInt( origin , bound );
// Randomly use uppercase rather than default lowercase.
if ( ThreadLocalRandom.current().nextBoolean() )
{
codePoint = Character.toUpperCase( codePoint );
}
matrix[ i ][ j ] = Character.toString( codePoint );
}
}
Dump to console.
System.out.println( Arrays.deepToString( matrix ) );
for ( int rowIndex = 0 ; rowIndex < matrix.length ; rowIndex++ ) // Rows.
{
for ( int columnIndex = 0 ; columnIndex < matrix[ rowIndex ].length ; columnIndex++ ) // Columns
{
String cell = matrix[ rowIndex ][ columnIndex ];
String output = Objects.isNull( cell ) ? " " : cell; // Ternary operator. Effectively a compact if-else statement.
System.out.print( output + " " );
}
System.out.println(); // Next line.
}
When run.
[[a, P, F, B, u, R, j], [G, o, F, H, z, L, null], [N, R, f, y, m, null, null], [U, f, F, j, null, null, null], [R, G, i, null, null, null, null], [G, b, null, null, null, null, null], [g, null, null, null, null, null, null]]
a P F B u R j
G o F H z L
N R f y m
U f F j
R G i
G b
g