One thing to note is that code is read frequently, to different "depths". This code:
PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "abc");
wakeLock.acquire();
is easy to "skim". It's 3 statements. First we come up with a PowerManager
. Then we come up with a WakeLock
. Then we acquire
the wakeLock
. I can see that really easily just by looking at the start of each line; simple variable assignments are really easy to recognise partially as "Type varName = ..." and just mentally skim over the "...". Similarly the last statement is obviously not the form of the assignment, but it only involves two names, so the "main gist" is immediately apparent. Often that's all I would need to know if I was just trying to answer "what does this code do?" at a highish level.
If I'm chasing a subtle bug that I think is here, then obviously I'll need to go over this in much more detail, and will actually remember the "..."s. But the separate statement structure still helps me do that one statement at a time (especially useful if I need to jump deeper into the implementation of the things being called in each statement; when I come back out I've fully understood "one unit" and can then move on to the next statement).
((PowerManager)getSystemService(POWER_SERVICE))
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag")
.acquire();
Now it's all one statement. The top level structure is not so easy to skim-read; in the original version of the OP, without linebreaks and indentation to visually communicate any structure, I would have had to count parentheses to decode it into a sequence of 3 steps. If some of the multi-part expressions are nested within each other rather than arranged as a chain of method calls, then it could still come out looking similar to this, so I have to be careful about trusting that without counting parentheses. And if I do trust the indentation and just skim ahead to the last thing as the presumed point of all this, what does .acquire()
tell me on its own?
Sometimes though, that can be what you want. If I apply your transformation half-way and wrote:
WakeLock wakeLock =
((PowerManeger)getSystemService(POWER_SERVICE))
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLockTage");
wakeLock.acquire();
Now this communicates to a quick skim "get a WakeLock
, then acquire
it". Even simpler than the first version. It's immediately obvious that the thing that is acquired is a WakeLock
. If obtaining the PowerManager
is just a sub-detail that's fairly insignificant to the point of this code, but the wakeLock
is important, then it could actually help to bury the PowerManager
stuff so it's natural to skim over it if you're just trying to quickly get an idea of what this code does. And not naming it communicates that it is only used once, and sometimes that's what's important (if the rest of the scope is very long, I'd have to read all that to tell whether it's ever used again; though using explicit sub-scopes can be another way to address that, if your language supports them).
Which brings up that it all depends on context and what you want to communicate. As with writing prose in natural language, there are always many ways to write a given piece of code that are basically equivalent in terms of information content. As with writing prose in natural language, how you choose between them should generally not be to apply mechanistic rules like "eliminate any local variable that only occurs once". Rather how you choose to write down your code will emphasise certain things and de-emphasise others. You should strive to make those choices consciously (including the choice to write less readable code for technical reasons at times), based on what you actually want to emphasise. Especially think about what will serve readers who just need to "get the gist" of your code (at various levels), since that will happen far more often than a very close expression-by-expression reading.