有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何调试库代码中发生的NullPointerException?

我正在用java提取一个ZIP文件:

ZipFile zipFile = new ZipFile(theZipFile);
  Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
    while(zipEntries.hasMoreElements()){
      ZipEntry entry = zipEntries.nextElement(); /// <---Nullpointer exception happens here
  }

代码执行已超过while(zipEntries.hasMoreElements()),但在提取ZipEntry时失败

奇怪的是hasMoreElements返回true,但在尝试取出元素时会出现null指针

异常来自JDK lib中的ZipFile类,我在调试器中看不到局部变量,因此如何找出Zip文件的错误

编辑: 堆栈跟踪:

java.lang.NullPointerException
    at java.util.zip.ZipFile.getZipEntry(ZipFile.java:529)
    at java.util.zip.ZipFile.access$900(ZipFile.java:56)
    at java.util.zip.ZipFile$1.nextElement(ZipFile.java:511)
    at java.util.zip.ZipFile$1.nextElement(ZipFile.java:481)

共 (2) 个答案

  1. # 1 楼答案

    我最近也遇到了同样的问题,所以我比较了JDK1.6和1.7相关的zip源代码

    真正的原因是JDK1.6将由构造函数jzentry开头,如下所示:

    ZipEntry ze = new ZipEntry(jzentry);
    
    ZipEntry(long jzentry) {
        initFields(jzentry);
    }
    

    但是在jdk1.7中,我们可以看到它的使用

    private ZipEntry getZipEntry(String name, long jzentry) {
        ZipEntry e = new ZipEntry(); // it did not use jzentry initial it
    

    当一些jar文件有空条目时,它将抛出异常

  2. # 2 楼答案

    以下是getZipEntry方法(从1.7.0_10开始):

    private ZipEntry getZipEntry(String name, long jzentry) {
        ZipEntry e = new ZipEntry();
        e.flag = getEntryFlag(jzentry);  // get the flag first
        if (name != null) {
            e.name = name;
        } else {
            byte[] bname = getEntryBytes(jzentry, JZENTRY_NAME);
            if (!zc.isUTF8() && (e.flag & EFS) != 0) {
                e.name = zc.toStringUTF8(bname, bname.length);
            } else {
                e.name = zc.toString(bname, bname.length);      // Line 529
            }
        }
        /* snip */
        return e;
    }
    

    在这行上抛出NullPointerException的唯一原因是ezcbnamenull

    e不能是null,因为它在该方法中被明确实例化

    zc不能是null

    public ZipFile(File file, int mode, Charset charset) throws IOException
    {
        /* snip */
        this.zc = ZipCoder.get(charset);
        /* snip */
    }
    
    static ZipCoder get(Charset charset) {
        return new ZipCoder(charset);
    }
    

    这意味着bname必须是null,这将很难调试getEntryBytes是一种{}方法:

    private static native byte[] getEntryBytes(long jzentry, int type);
    

    我将这样做:

    • 找出是那个特定的zip文件还是所有的zip文件。如果是特定的zip文件,请尝试重新制作它
    • 更新您的Java版本,可能有一个getEntryBytes的bug已经修复
    • 向Oracle提交错误报告