The 1.0 release of Java is dated January 1996 while Rust 1.0 was released in May 2015. Although age may not be an essential differentiator, some claim that the former has pedigree. Regardless of history, one obvious difference between Java and Rust is that the former runs on the JVM, which means it is just-in-time compiled. In short, Java can benefit from profile-based optimizations which (in theory) allow better performance than compile-time optimized code for certain workloads.
Another aspect which matters is that a typical Rust program consumes orders of magnitude less memory than an ordinary Java program. Although Java’s GC is very optimized and makes programming rather painless, Rust has a zero-sized runtime, for some large values of zero. There is a runtime, but it consists of establishing landing pads for panics which can even be overridden.
Rust is not as portable as Java, but backends for a number of targets can be obtained with reasonable effort as it is LLVM-based. Rust may be suitable for targets that are considered to be too small for the JVM because of the absence of a fat runtime and garbage collector.
What Java lacks and Rust offers is the following: Rust’s ownership- and lifetime-rules, which are upheld by the borrow checker allow it to get by without a GC. This also has its perks and disadvantages, because even though the compiler guarantees freedom from data-races, users will eventually bash their head against the borrow checker.