You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java 1.8+IDEA环境下Jar包运行字体读取异常问题排查

问题根源分析与解决方案

你的问题主要来自三个核心点:Jar包与IDE中资源路径的访问差异、成员变量初始化顺序错误,以及打包时资源文件是否被正确纳入Jar包。下面逐一拆解并给出解决办法:

1. Jar包中资源路径的访问问题

在IDE中运行时,资源文件(比如你的ARIALN.ttf)是存在于本地文件系统的目录里,getResourceAsStream能轻松找到,但打包成Jar后,资源是嵌入在Jar文件内部的,这时候路径写法和获取逻辑需要调整:

  • 你原代码中GameField.class.getResourceAsStream("assets/fonts/ARIALN.ttf")的路径是相对当前类的包路径。比如如果GameField在com.pumaex包下,它会去com/pumaex/assets/fonts/ARIALN.ttf找资源,而非你预期的classpath根目录下的assets/fonts/ARIALN.ttf。
  • 正确的资源获取方式有两种:
    • 给路径加前缀/,使用Class的getResourceAsStream:GameField.class.getResourceAsStream("/assets/fonts/ARIALN.ttf")(强制从classpath根目录查找)
    • 使用ClassLoader的getResourceAsStream(默认从classpath根目录查找,无需前缀):GameField.class.getClassLoader().getResourceAsStream("assets/fonts/ARIALN.ttf")

2. 成员变量初始化顺序导致的NullPointerException

看你原代码的变量声明:

private Font myArialNarrow;
{
    // 初始化myArialNarrow的代码块
}
private Font myFont1 = myArialNarrow.deriveFont(30f);

Java的成员变量初始化顺序是:实例变量 → 初始化块 → 构造函数。这里myFont1作为实例变量,会在初始化块执行前就被初始化,此时myArialNarrow还是null,调用deriveFont自然会抛出空指针异常。

解决办法:把myFont1的初始化移到初始化块或构造函数中:

private Font myArialNarrow;
private Font myFont1;
{
    try {
        InputStream is1 = GameField.class.getResourceAsStream("/assets/fonts/ARIALN.ttf");
        myArialNarrow = Font.createFont(Font.TRUETYPE_FONT, is1);
        myFont1 = myArialNarrow.deriveFont(30f);
    } catch (FontFormatException | IOException e) {
        e.printStackTrace();
    }
}

3. 确保资源被正确打包进Jar包

在IntelliJ IDEA中需要做两个确认:

  • 右键assets目录 → 选择Mark Directory as → Resources Root,标记为资源根目录,确保IDE打包时会将该目录下的文件纳入classpath。
  • 检查打包配置:进入File → Project Structure → Artifacts,确认你的Jar制品中包含了assets目录下的所有文件。

修正后的完整示例代码

结合以上所有要点,修正后的代码可以参考:

import java.awt.Font;
import java.awt.FontFormatException;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;

public class GameField {
    private Font myArialNarrow;
    private Font myFont1;

    // 初始化块
    {
        try (InputStream is = new BufferedInputStream(
                GameField.class.getClassLoader().getResourceAsStream("assets/fonts/ARIALN.ttf"))) {
            if (is == null) {
                throw new IOException("Font file not found in classpath!");
            }
            myArialNarrow = Font.createFont(Font.TRUETYPE_FONT, is);
            myFont1 = myArialNarrow.deriveFont(30f);
        } catch (FontFormatException | IOException e) {
            System.err.println("Failed to load font:");
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        GameField field = new GameField();
        System.out.println("Loaded font: " + field.myFont1);
    }
}

另外,你的补充代码中loadFile方法声明了throws ClassNotFoundException,这是多余的,getResourceAsStream不会抛出该异常,可以直接移除。


内容的提问来源于stack exchange,提问作者pumaex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 22:37:53