Generally speaking, the javac compiler doesn't generate dead code. If something can be statically determined to be unreachable, the compile will fail. For example:
void foo() {
throw new RuntimeException();
doStuff();
}
This results in an "unreachable statement" failure. You can "hint" to the compiler that you want to do this anyway:
void foo() {
if (true) throw new RuntimeException();
doStuff();
}
However, the compiler still knows that the call to doStuff() is unreachable, and discards it.
If you did manage to get dead code into a DEX file, the bytecode verifier will optionally tell you about it -- look for DEAD_CODE_SCAN
in the verifier source.
All of that is for dead code inside a method. For identifying whole methods that are never actually called, you can use ProGuard (which is an optional but officially supported part of Android app builds). This can false-positive and remove methods that are never called directly but may be called through reflection, so manual overrides are sometimes required.