首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Java PrintWriter错误

Java PrintWriter错误
EN

Stack Overflow用户
提问于 2016-02-23 23:40:36
回答 2查看 1.8K关注 0票数 6

我是个老读者,但却是第一次写字。

我目前正在尝试在我们的代码库中使用AspectJ实现一个记录器。AspectJ似乎工作得很好,但我遇到了非常奇怪的Java错误。我是一个长期的C++和.Net开发人员,仍然在适应Java语言的世界,所以如果这是一个愚蠢的问题,我道歉。

我的代码试图捕获异常,并将相关信息记录到文本文件中。陷阱工作得很好,但我注意到当我部署时,我没有得到任何数据。我在一个Java反编译器中打开了我的类文件,并注意到PrintWriter似乎生成了一个错误。我从来没有见过这样的问题,所以我希望你可能会有任何见解。

代码语言:javascript
运行
复制
package mil.uscg.c3cen.vic.aspect;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.JoinPoint;

@Aspect
public class LoggingAspect
{
    private final String LOG_FILE = "aspectLog.txt";
    private final File file = new File(LOG_FILE);

    private LoggingAspect() 
    { 

    }

    private void logException(String msg) 
    {
        try 
        {
            if(!file.exists())
                file.createNewFile();
        }
        catch(IOException e) 
        {

        }

        try (FileWriter fw = new FileWriter(file); 
               BufferedWriter bw = new BufferedWriter(fw);
               PrintWriter pw = new PrintWriter(bw)) 
        {
            pw.println(msg);
        }
        catch(IOException e)
        {

        }
    }

    private String getSimpleFunctionInfo(String className, String     function, Object[] args)
    {
        StringBuilder builder = new StringBuilder();
        builder.append(". Method: ");
        builder.append(className);
        builder.append(".");
        builder.append(function);

        if(args.length == 0)
        {
            builder.append("()");
            return builder.toString();
        }

        builder.append("(");

        for(Object o : args)
        {
            builder.append(o.toString());
            builder.append(",");
        }
        // Replace the comma for the last param with a closing parenthesis
        int len = builder.length();
        builder.replace(len -1, len, ")");

        return builder.toString();
    }

    // Returns a formatted exception. "Exception.ErrorMessage"
    private String getSimpleExceptionInfo(String name, String msg)
    {
        StringBuilder builder = new StringBuilder();
        builder.append("Exception caught: ");
        builder.append(name);
        builder.append(". Message: ");
        builder.append(msg);
        return builder.toString();
    }


   @AfterThrowing(pointcut = "execution(* mil.uscg.c3cen.*.*.*(..)) "
       //+ "&& !within(mil.uscg.c3cen.vic.aspect.*) "
       , throwing = "excep")
    public void afterThrowing(JoinPoint jp, Throwable excep) throws Throwable
    {
        String ex = getSimpleExceptionInfo(excep.getClass().getSimpleName(), 
                                                             excep.getMessage());

        String name = getSimpleFunctionInfo(jp.getSignature().getDeclaringType().getSimpleName(), 
                                                               jp.getSignature().getName(), 
                                                               jp.getArgs());

        StringBuilder builder = new StringBuilder();
        builder.append(ex);
        builder.append(name);

        logException(builder.toString());
    } 
}

在类文件中,除了函数logException之外,所有内容看起来都与预期的一样。

代码语言:javascript
运行
复制
/* Error */
  private void logException(String msg)
  {
    // Byte code:
    //   0: aload_0
    //   1: getfield 25 mil/uscg/c3cen/vic/aspect/LoggingAspect:file    Ljava/io/File;
    //   4: invokevirtual 32    java/io/File:exists ()Z
    //   7: ifne +15 -> 22
    //   10: aload_0
    //   11: getfield 25    mil/uscg/c3cen/vic/aspect/LoggingAspect:file    Ljava/io/File;
    //   14: invokevirtual 36   java/io/File:createNewFile  ()Z
    //   17: pop
    //   18: goto +4 -> 22
    //   21: pop
    //   22: aconst_null
    //   23: astore_2
    //   24: aconst_null
    //   25: astore_3
    //   26: new 39 java/io/FileWriter
    //   29: dup
    //   30: aload_0
    //   31: getfield 25    mil/uscg/c3cen/vic/aspect/LoggingAspect:file    Ljava/io/File;
    //   34: invokespecial 41   java/io/FileWriter:<init>   (Ljava/io/File;)V
    //   37: astore 4
    //   39: new 44 java/io/BufferedWriter
    //   42: dup
    //   43: aload 4
    //   45: invokespecial 46   java/io/BufferedWriter:<init>   (Ljava/io/Writer;)V
    //   48: astore 5
    //   50: new 49 java/io/PrintWriter
    //   53: dup
    //   54: aload 5
    //   56: invokespecial 51   java/io/PrintWriter:<init>  (Ljava/io/Writer;)V
    //   59: astore 6
    //   61: aload 6
    //   63: aload_1
    //   64: invokevirtual 52   java/io/PrintWriter:println (Ljava/lang/String;)V
    //   67: aload 6
    //   69: ifnull +24 -> 93
    //   72: aload 6
    //   74: invokevirtual 55   java/io/PrintWriter:close   ()V
    //   77: goto +16 -> 93
    //   80: astore_2
    //   81: aload 6
    //   83: ifnull +8 -> 91
    //   86: aload 6
    //   88: invokevirtual 55   java/io/PrintWriter:close   ()V
    //   91: aload_2
    //   92: athrow
    //   93: aload 5
    //   95: ifnull +43 -> 138
    //   98: aload 5
    //   100: invokevirtual 58  java/io/BufferedWriter:close    ()V
    //   103: goto +35 -> 138
    //   106: astore_3
    //   107: aload_2
    //   108: ifnonnull +8 -> 116
    //   111: aload_3
    //   112: astore_2
    //   113: goto +13 -> 126
    //   116: aload_2
    //   117: aload_3
    //   118: if_acmpeq +8 -> 126
    //   121: aload_2
    //   122: aload_3
    //   123: invokevirtual 59  java/lang/Throwable:addSuppressed   (Ljava/lang/Throwable;)V
    //   126: aload 5
    //   128: ifnull +8 -> 136
    //   131: aload 5
    //   133: invokevirtual 58  java/io/BufferedWriter:close    ()V
    //   136: aload_2
    //   137: athrow
    //   138: aload 4
    //   140: ifnull +66 -> 206
    //   143: aload 4
    //   145: invokevirtual 65  java/io/FileWriter:close    ()V
    //   148: goto +58 -> 206
    //   151: astore_3
    //   152: aload_2
    //   153: ifnonnull +8 -> 161
    //   156: aload_3
    //   157: astore_2
    //   158: goto +13 -> 171
    //   161: aload_2
    //   162: aload_3
    //   163: if_acmpeq +8 -> 171
    //   166: aload_2
    //   167: aload_3
    //   168: invokevirtual 59  java/lang/Throwable:addSuppressed   (Ljava/lang/Throwable;)V
    //   171: aload 4
    //   173: ifnull +8 -> 181
    //   176: aload 4
    //   178: invokevirtual 65  java/io/FileWriter:close    ()V
    //   181: aload_2
    //   182: athrow
    //   183: astore_3
    //   184: aload_2
    //   185: ifnonnull +8 -> 193
    //   188: aload_3
    //   189: astore_2
    //   190: goto +13 -> 203
    //   193: aload_2
    //   194: aload_3
    //   195: if_acmpeq +8 -> 203
    //   198: aload_2
    //   199: aload_3
    //   200: invokevirtual 59  java/lang/Throwable:addSuppressed   (Ljava/lang/Throwable;)V
    //   203: aload_2
    //   204: athrow
    //   205: pop
    //   206: return
    // Line number table:
    //   Java source line #28   -> byte code offset #0
    //   Java source line #29   -> byte code offset #10
    //   Java source line #30   -> byte code offset #18
    //   Java source line #31   -> byte code offset #21
    //   Java source line #36   -> byte code offset #22
    //   Java source line #36   -> byte code offset #26
    //   Java source line #37   -> byte code offset #39
    //   Java source line #38   -> byte code offset #50
    //   Java source line #40   -> byte code offset #61
    //   Java source line #41   -> byte code offset #67
    //   Java source line #42   -> byte code offset #205
    //   Java source line #46   -> byte code offset #206
    // Local variable table:
    //   start  length  slot    name    signature
    //   0  207 0   this    LoggingAspect
    //   0  207 1   msg String
    //   23 1   2   localObject1    Object
    //   80 28  2   localObject2    Object
    //   112    92  2   localObject3    Object
    //   25 1   3   localObject4    Object
    //   106    17  3   localThrowable1 Throwable
    //   151    17  3   localThrowable2 Throwable
    //   183    17  3   localThrowable3 Throwable
    //   37 140 4   fw  java.io.FileWriter
    //   48 84  5   bw  java.io.BufferedWriter
    //   59 28  6   pw  java.io.PrintWriter
    //   21 1   12  localIOException1   java.io.IOException
    //   205    1   13  localIOException2   java.io.IOException
    // Exception table:
    //   from   to  target  type
    //   0  18  21  java/io/IOException
    //   61 67  80  finally
    //   50 93  106 finally
    //   39 138 151 finally
    //   26 183 183 finally
    //   22 205 205 java/io/IOException
  }

这真的难倒了我,所以任何信息都将非常感谢。谢谢!

EN

回答 2

Stack Overflow用户

发布于 2016-02-27 21:53:24

好吧,我尝试了Java8和当前的AspectJ 1.8.8。您的方面按预期工作(我编译它时没有做任何更改)。它只是有点过于复杂,应该简化。此外,您可能只是错误地计算了切入点中的.*数量。

如果我在您的建议方法的开头添加System.out.println(jp);,以便在控制台上看到一些东西,并在这个示例驱动程序类上运行您的方面...

代码语言:javascript
运行
复制
package mil.uscg.c3cen.foo;

public class Application {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            try {
                doSomething();
            }
            catch (Exception e) {}
        }
    }

    public static void doSomething() {
        System.out.println("Calculation result = " + multiply(add(3, 4), 5));
        System.out.println("Calculation result = " + divide(add(5, 6), 0));
    }

    private static int add(int summand1, int summand2) {
        return summand1 + summand2;
    }

    private static int multiply(int factor1, int factor2) {
        return factor1 * factor2;
    }

    private static int divide(int dividend, int divisor) {
        return dividend / divisor;
    }
}

..。控制台日志如下所示:

代码语言:javascript
运行
复制
Calculation result = 35
execution(int mil.uscg.c3cen.foo.Application.divide(int, int))
execution(void mil.uscg.c3cen.foo.Application.doSomething())
Calculation result = 35
execution(int mil.uscg.c3cen.foo.Application.divide(int, int))
execution(void mil.uscg.c3cen.foo.Application.doSomething())
Calculation result = 35
execution(int mil.uscg.c3cen.foo.Application.divide(int, int))
execution(void mil.uscg.c3cen.foo.Application.doSomething())

正如您所看到的,正如预期的那样,只有在调用层次结构中向上抛出异常的方法(直到它们被捕获)才会被记录。日志文件aspectLog.txt的内容如下:

代码语言:javascript
运行
复制
Exception caught: ArithmeticException. Message: / by zero. Method: Application.main([Ljava.lang.String;@f6f4d33)

需要改进的地方:

  • 也许你想有一个更稳定的切入点来定位mil.uscg.c3cen的所有子程序包。“该包及其所有子包中的所有方法执行”的语法应该是execution(* mil.uscg.c3cen..*(..)).
  • There是日志文件使用逻辑中的一个错误:只要发生第一个异常,而日志文件还不存在,它就会被记录下来,日志文件会立即关闭。任何后续的异常都不会被记录下来,这可能不是您想要的。只要JVM启动并运行,您就可能希望将多个异常记录到同一个文件中。因此,您不希望在每次写入之后关闭日志文件,而是在JVM生命周期结束时在JVM关闭钩子中注意这一点。Try with (auto-closeable)资源只有在运行代码的某一部分后确实想要关闭它们时才有用。顺便说一句,你可以通过定期刷新编写器来避免关闭钩子,例如在每次println调用之后。
  • 我在这里不讨论线程和同步问题,这需要更多的注意。假设您有一个单线程application.
  • Maybe,您还希望截获构造函数中的异常并将其添加到切入点中。

改进和简化的方面:

代码语言:javascript
运行
复制
package mil.uscg.c3cen.vic.aspect;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class LoggingAspect {
    private static final String LOG_FILE = "aspectLog.txt";

    private final PrintWriter logWriter; 

    public LoggingAspect() throws FileNotFoundException {
        logWriter = new PrintWriter(new FileOutputStream(LOG_FILE));
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                logWriter.close();
            }
        });
    }

    @AfterThrowing(
        pointcut =
            "(execution(* mil.uscg.c3cen..*(..)) || execution(mil.uscg.c3cen..new(..)))" +
            " && !within(mil.uscg.c3cen.vic.aspect..*) ",
        throwing = "excep"
    )
    public void afterThrowing(JoinPoint jp, Throwable excep) throws Throwable {
        //System.out.println(excep + " -> " + jp);
        logWriter.println(excep + " -> " + jp);
    }
}

构造函数抛出异常的扩展代码示例:

代码语言:javascript
运行
复制
package mil.uscg.c3cen.foo;

public class Application {
    public Application() {
        System.out.println(1/0);
    }

    public static void doSomething() {
        System.out.println("Calculation result = " + multiply(add(3, 4), 5));
        System.out.println("Calculation result = " + divide(add(5, 6), 0));
    }

    private static int add(int summand1, int summand2) {
        return summand1 + summand2;
    }

    private static int multiply(int factor1, int factor2) {
        return factor1 * factor2;
    }

    private static int divide(int dividend, int divisor) {
        return dividend / divisor;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            try {
                doSomething();
            }
            catch (Exception e) {}
        }
        try {
            new Application();
        }
        catch (Exception e) {}
    }
}

控制台日志:

代码语言:javascript
运行
复制
Calculation result = 35
Calculation result = 35
Calculation result = 35

日志文件:

代码语言:javascript
运行
复制
java.lang.ArithmeticException: / by zero -> execution(int mil.uscg.c3cen.foo.Application.divide(int, int))
java.lang.ArithmeticException: / by zero -> execution(void mil.uscg.c3cen.foo.Application.doSomething())
java.lang.ArithmeticException: / by zero -> execution(int mil.uscg.c3cen.foo.Application.divide(int, int))
java.lang.ArithmeticException: / by zero -> execution(void mil.uscg.c3cen.foo.Application.doSomething())
java.lang.ArithmeticException: / by zero -> execution(int mil.uscg.c3cen.foo.Application.divide(int, int))
java.lang.ArithmeticException: / by zero -> execution(void mil.uscg.c3cen.foo.Application.doSomething())
java.lang.ArithmeticException: / by zero -> execution(mil.uscg.c3cen.foo.Application())

看最后一行,你可以看到构造函数中的异常。

如果您想要美化一下异常日志记录输出,类似于您的原始方面所做的那样,请执行以下操作:

代码语言:javascript
运行
复制
logWriter.println(excep.getClass().getSimpleName() + " -> " + jp.getSignature());

然后,日志文件变为:

代码语言:javascript
运行
复制
ArithmeticException -> int mil.uscg.c3cen.foo.Application.divide(int, int)
ArithmeticException -> void mil.uscg.c3cen.foo.Application.doSomething()
ArithmeticException -> int mil.uscg.c3cen.foo.Application.divide(int, int)
ArithmeticException -> void mil.uscg.c3cen.foo.Application.doSomething()
ArithmeticException -> int mil.uscg.c3cen.foo.Application.divide(int, int)
ArithmeticException -> void mil.uscg.c3cen.foo.Application.doSomething()
ArithmeticException -> mil.uscg.c3cen.foo.Application()
票数 2
EN

Stack Overflow用户

发布于 2016-02-23 23:58:30

你还没说出问题出在哪呢。如果您在logException中遇到未捕获异常的问题,那么就捕获它并进行调查。最有可能的是打开文件时的权限问题,或者(例如在windows上)操作系统不允许通过多个线程访问文件。

对于第二个问题,字节码是完全清除的。第一部分非常简单,紧跟在您编写的代码之后。第二部分处理关闭资源,并将可能捕获的异常作为抑制异常添加到已引发的异常中。这段代码有点长,但还是以相反的方向跟在资源初始化之后。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35581814

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档