tags:

views:

359

answers:

7

EDIT: I would love to read reactions to Steve Reed's AOP approach. Comments to his answer are encouraged!

I'm a novice, and at some point I realized it would be helpful to know the contents of a variable during program execution. So I started doing this:

EDIT: fixed this. Used to be: var + ": " + var, which was totally wrong. Dumb typo.

System.err.println ( "var: " + var );

Later I learned that this was common practice. At least, where a debugger was unavailable or unwanted.

I use a basic text editor, and typing the print statement every time I need to debug a variable is pretty tiresome, so I thought, why not something like this:

void dbug ( Object obj )
{
    String variableName = obj.somehowGetVariableName();
    String variableContents = obj.toString();
    System.out.println ( variableName +": " + variableContents );
}

But apparently getting the variable name is easier said than done.

java-reflection-how-to-get-the-name-of-a-variable

Am I stuck with:

System.err.println ( "var: " + var );

Or is there a popular shorthand version of this?

+3  A: 

Have a look at Simple Logging Framework, it allows you to type:

Object obj1, obj2;
log.debug("This is object 1: {}, and this is object 2: {}", obj1, obj2);
Tim
@Tim - does that reflectively print the contents of the object or does it call toString() on the object ?
Brian Agnew
I think it just does a toString() so this doesn't offer much other than avoiding the String concatenation.
pjp
@pjp- if that's the case I don't think it's hugely useful in this scenario, is it ?
Brian Agnew
Thanks for that link, Tim. I'm checking it out right now. It may take me a while to find out if this, or other logging techniques, are less hassle than my trusty print statement.
Lasoldo Solsifa
Tim
+2  A: 

Some thoughts:

  1. I would implement toString() on objects of interest, and in that print out the members in a friendly fashion (e.g. convert timestamps to a readable format etc.). I usually choose a format like:

    Object[member1=,member2=...]
    

    Otherwise printing the object alone will give you the classname plus the identity hash code, and (as you've discovered) that's not hugely useful!

    Commons has a facility to do this automatically. But here's a simple toString() tutorial which I think is more appropriate.

  2. There are logging frameworks that you may be interested in in the future. e.g. check out Log4j. At the moment, however, I wouldn't worry about that.

Brian Agnew
Just watchout implementing a toString method that lists all of the members on class containing lazily loaded members as this will force them all to be created. (e.g. Hibernate collections).
pjp
@pjp - good point worth noting
Brian Agnew
I admit that I always assumed the existence of a sensible toString(). I also assumed primitives could be actual parameters where Object was expected. Thank you for the links! They look like they will be helpful.
Lasoldo Solsifa
+5  A: 

I wouldn't try and write any fancy methods around printing out debugging info. Just stick with either LOG.debug(...) if you are using a logger or System.err.println(...) otherwise.

You may wish to use String.format("var=%s val=%s", "VarName", val) instead of the String concatenation.

Make sure that you override the toString method in each of your classes to provide meaningful debug info.

At the end of the day it's often easier to fire up the debugger and take a look to see what's going on instead of having to trace through loads of logged debug lines.

The only time when i'd use your kind of debug method would be if my application maintained all of the state inside a map which I could easily print out the key value pairs (e.g. the session map in a web application).

pjp
Thanks for that! I definitely agree that your formatted string approach is better than my string concatenation. Using it henceforth.
Lasoldo Solsifa
+2  A: 

Personally I don't suggest to use sysout statements anywhere. You should always use a debugger (using some IDE). I cannot imagine where this wouldn't be wanted.

Otherwise I'm suggesting logging frameworks like log4j, but again, this already gets more complicated where I would again then switch to a real IDE with debugger.

Juri
Logging is always useful for production systems when you cannot always fire up a debugger. They're not too complicated to setup once you find a sample Log4J config file :)
pjp
Indeed... switching to a good IDE seems like a good step for this person.
jsight
Thanks, Juri, and I'm sure you're right. I always try to use the simplest tool possible, and my projects are small, so I have not been compelled to use an IDE yet. I have tried Eclipse, though, and it is very easy to see that the advantages are many.
Lasoldo Solsifa
I'd say that your need to inspect program state compels you strongly to use a debugger and thus an IDE.
Michael Borgwardt
@Lasoldo: You should definitely switch to Eclipse. I always use it, even for a single-class project. Why to bother with notepad, searching the right packages to import and compile over command line, when Eclipse does it for you in the background. Moreover the debugger comes for free, so....Using println statements is considered bad practice
Juri
Yes, you are right. My original motivation was the urge to learn programming from the ground up, the "hard way", if you will. I guessed that this meant using only a text editor and the command line. Now it's probably time to move on to an IDE.
Lasoldo Solsifa
+2  A: 

I think that System.err.format is what you want:

System.err.format("var: %s\n", var);

is a shorthand for:

System.err.println(String.format("var: %s", var));
dfa
Hey, now we're getting somewhere. Thanks for this one. pjp suggested using String.format("var=%s val=%s", "VarName", val), and sure enough, yours is shorter.
Lasoldo Solsifa
A: 

You can get access to the variable names with AOP and compile-time weaving. The nice thing about this is that if you don't do the weaving, you don't add the debug logging code and your runtime code is leaner and quicker as a result.

Here's an example of using AspectJ to throw an example when a field is set to null. Note the usage of "joinPoint.getSignature()" to get access to the code metadata.

@Aspect
public class NotNullValidator {

   @Pointcut(value = "set(@com.acme.NotNull * *.*) && args(valueBeingSet)")
   private void setOfNonNullField(final Object valueBeingSet) { }

   @Before(value = "setOfNonNullField(valueBeingSet)")
   public void validate(final JoinPoint joinPoint, final Object valueBeingSet) {
      if (valueBeingSet == null) {
         throw new NullPointerException("Cannot set " + joinPoint.getSignature().getName() + " to null.");
      }
   }
}

See JoinPoint Javadoc to see what else you can get (line numbers, source and target objects, etc).

Steve Reed
This looks pretty interesting, but it is over my hobbyist-level head, that's for sure! It will take me a while to figure out how to test it. Maybe someone could comment on this approach... any takers?
Lasoldo Solsifa
It definitely takes a while to wrap ones mind around AOP in general, but I've been able to leverage the above approach pretty well. The aspect above allows me to simple annotate fields with a @NotNull and ANY time they are set the null-checking code is "woven" in during the compile. It's really nice and quite a time-saver.
Steve Reed
A: 

It's a stretch, but...

You're getting advice to use an IDE instead of a simple text editor. I'd go along with that, 100%.

You're getting advice to use a logging framework or a debugger instead of println() calls. Well, sure, but...

Better yet is unit tests. Don't ask what it is - tell it what you expect. Then, the integrated unit-testing framework (junit, typically) will verify that you're getting what you expect. The more I use unit tests, the less I need debugging and the less I need println's. And when something changes, the testing framework tells me - I don't need to manually re-evaluate every test's output, just watch the bar.

Unit tests are better than debugging, better than logging. They're not a 100% replacement for debugging and logging, but start using them and you'll find much less need for those tedious activities.

Carl Manaster
I think you're spot on here. When I did an Eclipse tutorial, it was all about writing the tests first, then basically letting the IDE create the methods from them. I have always tried to use the lightest-weight tools possible, and have stuck with the text editor, in spite of the tedium it induces. I may be at the point where this ideology is counter-productive. Thanks for the insight.
Lasoldo Solsifa