It's good if you don't want to care about those details, it's bad if you really care about those details for performance reasons.
The former is a nightmare for security and productivity, the latter is a nightmare for performance.
It can decide to heap-allocate or stack-allocate objects (when you new them) based on escape analysis, which is a JIT optimization. But that's very different from heap-allocating variables.
Regardless, whether something is a local or not in Java still varies depending on the JIT's decisions. (Or rather, the JIT does not see local/non-local variables, only lifetimes, and whether the lifetime may extend past the JIT's current view.)
In Go, if you have a local of type int, and that local is captured by a closure, it will be allocated on the heap to extend its lifetime. Java doesn't need to do this because it requires captures to be effectively final. On the other hand, C# does the same thing as Go.
You don't have to think about stack vs. heap allocation in Go unless you're writing performance sensitive code. You could pretend that Go heap allocates everything and still read and write Go code without any problems.
Thankfully plenty of other GC based languages hadn't made the same mistake.