简体   繁体   中英

Looking for an easier way to write debugging print statements in Java

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?

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 (eg the session map in a web application).

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

class Example {
    static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(Example.class);

    void doSomething(Object obj1, Object obj2) {
        LOG.debug("This is object 1: {}, and this is object 2: {}", obj1, obj2);
    }
}

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));

Some thoughts:

  1. I would implement toString() on objects of interest, and in that print out the members in a friendly fashion (eg 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. eg check out Log4j . At the moment, however, I wouldn't worry about that.

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.

If you use IntelliJ IDEA, you can use the "Live template" shortcut for printing to System.out such as soutp (and then a TAB) to debug the method parameters, soutv to trace the name of a variable along with it's value, etc.

To read the list of shortcuts\\modify it, go to File->Settings->Live Templates->Output

My first advice is: stick to java.util.logging package. There is really no need for 3rd party logging libraries.

  1. Get instance of java.util.Logger

    Logger logger = Logger.getLogger("some.package.XyzClassName");

  2. Log objects (using placeholder {N})

    logger.log(Level.INFO, "logging stuff {0} and {1}", new Object[]{new String("Test"), 1222});

In case of user defined classes you need to have some sensible toString() override implementation, because this method is called when replacing placeholder in message {N}.

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 exception 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).

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.

Have you tried DoodleDebug? It's an Eclipse plugin and meant to be as easy as System.out.println() but much more powerful.

It can be found here: http://scg.unibe.ch/wiki/projects/DoodleDebug

I would recommend you to properly configure and use Apache Log4J. System.out or System.err lines cause a lot of delay in execution of program. (You can confirm this by adding some time info that how much time your program takes without System.out etc and how much without these lines.)

Logging APIs use separate threads to log your logging info in log files, thats why they are more useful in realistic applications. Also logging APIs like Log4J give a lot of control over how to configure and format your logs. For example look here a few logs generated from Log4J:

2012-01-05 15:16:41,730 [main] 16   DEBUG dmfssecbuild.IOUtil  - 
2012-01-05 15:16:41,730 [main] 16   DEBUG dmfssecbuild.IOUtil  - Application Configs Loaded
2012-01-05 15:16:41,730 [main] 16   DEBUG dmfssecbuild.Constants  - Running Application between dates.
2012-01-05 15:16:41,730 [main] 16   DEBUG dmfssecbuild.Constants  - Sat Jan 01 00:00:00 GMT+05:00 2011 From Date 
2012-01-05 15:16:41,730 [main] 16   DEBUG dmfssecbuild.Constants  - Mon Dec 31 00:00:00 GMT+05:00 2012 To Date 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM