Reputation: 38257
How do you set variables which contain the class name, like TAG
in android.util.Log
, while respecting Dont-Repeat-Yourself?
These are some possibilities:
In Google code, it is often used like
public class Classname {
public final String TAG = "Classname";
which repeats the classname and was not refactor-renamed correctly in AndroidStudio (no String
s were).
Then, there is a dynamic variant
public class Classname {
public final String TAG = getClass().getName();
which does not repeat the Classname, thus seems better, yet is less readable.
Or, you could make TAG static
(this might be premature optimization). Apart from the official version above, you could get the name in code like
public class Classname {
public final static String TAG
= new Object() { }.getClass().getEnclosingClass().getName();
which is way less readable, and does have problems with inheritance (being static).
What is the best practice concerning this?
Is there a better way than 1-3? (Or is this a wrong approach?)
Upvotes: 0
Views: 247
Reputation: 38257
@JeffMiller gave the example in the ClassLogger class of his sormula project. In the class Logger
, he uses
StackTraceElement[] stes = new Throwable().getStackTrace();
int e = stes.length - 1;
for (int i = 0; i < e; ++i) {
if (stes[i].getClassName().equals(classLoggerClassName)) {
// next on stack is the class that created me
log = LoggerFactory.getLogger(stes[i + 1].getClassName());
break;
}
}
to get the caller's class name.
@FlorentBayle said in the comments that
public final static String TAG = Classname.class.getName();
should be refactored correctly. (And is more readable than variant 3 above).
This is also the approach used by third-party logging frameworks like SLF4J. It is initialized via
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
Upvotes: 1
Reputation: 17955
I have gone with the dynamic approach in the past:
public class Classname {
public final String TAG = getClass().getName();
It is not that unreadable, and it is self-contained.
For more complex cases of DRY-ness, there is always the possibility of creating your own annotations, and then either
Using the second approach, you could have something like
@ReplaceWithClassName("TAG")
public class Classname {
public final String TAG;
And then you would iterate through all classes annotated with @ReplaceWithClassName
filling in the blanks as an initialization step (more on iterating through annotated classes here; more on changing a final String here).
Annotations, introspection and code-generation provide great flexibility and power. Therefore, use wisely if you use them at all. For this particular case, the "dynamic approach" is much more readable.
Upvotes: 1