In a method, such as main1 and main2, there are supposed to be statements.
MethodDeclaration:
MethodHeader MethodBody
MethodBody:
Block
;
Block:
{ BlockStatements(opt) }
BlockStatements:
BlockStatement
BlockStatements BlockStatement
BlockStatement:
LocalVariableDeclarationStatement
ClassDeclaration
Statement
500; is not a statement, but Math.random(); and calledFn(); are statements.
Let's see what exactly constitutes a "statement":
Statement:
StatementWithoutTrailingSubstatement
LabeledStatement
IfThenStatement
IfThenElseStatement
WhileStatement
ForStatement
StatementWithoutTrailingSubstatement:
Block
EmptyStatement
ExpressionStatement
AssertStatement
SwitchStatement
DoStatement
BreakStatement
ContinueStatement
ReturnStatement
SynchronizedStatement
ThrowStatement
TryStatement
The important thing to note is that there is a kind of statement called an "expression statement". Let's see the syntax of that:
ExpressionStatement:
StatementExpression ;
StatementExpression:
Assignment
PreIncrementExpression
PreDecrementExpression
PostIncrementExpression
PostDecrementExpression
MethodInvocation
ClassInstanceCreationExpression
An ExpressionStatement is just a StatementExpression followed by a ;. Note that not all expressions are StatementExpressions. 500 is a literal, which is a kind of expression, but not a kind of StatementExpression. On the other hand, Math.random() and calledFn() are method invocations, which are StatementExpressions.
All the syntax shown are excerpts from section 18 of the Java Language Specification.
But aren't both functions doing the exact same thing?
Syntactically, they are not. In the method body of main2, there is a literal followed by a ;, which the compiler doesn't recognise as a statement. In main1, the compiler recognises calledFn() as a method invocation, and so calledFn(); is a statement.
As humans, we tend to mentally "replace" the method invocation with the value that it returns, but the compiler doesn't do that when parsing your code.