Java Stream 排序与 Comparator 的空指针处理,以及 IDEA 调试里 null 不显示的坑
记录一次排序 NPE 的排查和解决,顺便说下 IDEA 调试集合时 null 元素不显示的问题怎么调整。
支持通配符SSL证书、多域名证书、IP证书。适配ACME接口, 支持Zerossl、Let's Encrypt和Google等渠道。登录已有账号
2026-07-03 13:15:39 Aspose.PDF 字体加载 TTC TTF Java
平时用 Aspose.PDF 搞报告生成,碰上一个需求:必须用客户指定的字体包。大部分字体是 .ttf,直接就用上了,偏偏有几个是 .ttc。
一开始理所当然以为 FontRepository.openFont() 能搞定,扔进去直接异常,才发现 Aspose.PDF 不认 TTC 这个格式。
先看怎么加载普通的 .ttf 文件,这块没坑,核心就是 FontRepository.openFont(),支持传文件路径也支持 InputStream。我们一般习惯用流,后面也方便从 classpath 或者资源目录里读。下面是一段最简代码,依赖的 Aspose.PDF 版本是 23.1。
import com.aspose.pdf.Document;
import com.aspose.pdf.Page;
import com.aspose.pdf.TextFragment;
import com.aspose.pdf.TextState;
import com.aspose.pdf.FontRepository;
import com.aspose.pdf.Font;
import java.io.FileInputStream;
import java.io.InputStream;
public class LoadLocalFont {
public static void main(String[] args) throws Exception {
String fontPath = "resources/font.ttf";
InputStream fontStream = new FileInputStream(fontPath);
Font customFont = FontRepository.openFont(fontStream);
Document pdfDocument = new Document();
Page page = pdfDocument.getPages().add();
TextFragment textFragment = new TextFragment("这是一段使用本地字体的中文文本");
TextState textState = textFragment.getTextState();
textState.setFont(customFont);
textState.setFontSize(12);
page.getParagraphs().add(textFragment);
pdfDocument.save("output/LocalFontExample.pdf");
System.out.println("PDF 生成成功,已应用本地字体!");
}
}
这里有两个点容易出问题:一是路径,stream 读不到就检查下相对路径或者用绝对路径先试试;二是中文乱码,很多 .ttf 文件不含中文字形,比如你拿个英文专用字体去打中文,出来肯定是方块,所以得确认字体文件本身支持中文,像 SimSun、Noto Sans SC 之类。
回到 TTC。直接传 .ttc 文件给 openFont() 会报错,这条路不通。实际中有两种绕法,根据场景选就行。
如果运行环境已经装了目标字体(比如 Windows 上微软雅黑对应的文件是 msyh.ttc,但系统里已经注册了“微软雅黑”这个字体名称),最省事的办法就是走系统字体名称加载,不碰文件。用 FontRepository.findFont("微软雅黑") 直接拿到 Font 对象,Aspose.PDF 会调系统字体引擎,完全不感知底层是不是 TTC。缺点也很明显:部署环境必须预装字体。
要是扔进 Docker 镜像里跑,或者服务器没装桌面环境,这个方法就不可用了。代码大概这样:
import com.aspose.pdf.*;
public class LoadSystemFont {
public static void main(String[] args) throws Exception {
Document pdfDocument = new Document();
Page page = pdfDocument.getPages().add();
TextFragment text = new TextFragment("这是系统字体(微软雅黑)的中文文本");
TextState textState = text.getTextState();
textState.setFont(FontRepository.findFont("微软雅黑"));
textState.setFontSize(12);
page.getParagraphs().add(text);
pdfDocument.save("output/SystemFontExample.pdf");
System.out.println("PDF 生成成功,使用系统字体!");
}
}
如果你的场景不允许依赖系统字体,或者必须固定某个字体版本,那就得从 .ttc 里把需要的子字体拆出来,转成 .ttf 再用。我用的是 FontForge,打开 .ttc 后能看到里面包含多个子字体,选中你要的那个导出为 .ttf 就行了。
也可以用 Python 的 fonttools 里的 ttx 命令行工具,脚本化处理更方便。提取出来的 .ttf 和普通字体文件没区别,继续走上面加载 TTF 的流程就行。
不管走哪种方案,拿到字体名称是很关键的一步。Windows 下直接去 C:\Windows\Fonts 里找到字体文件,右键属性看“字体名称”,注意显示名称可能带空格,要和 findFont() 里的字符串完全一致。Linux 或 macOS 可以用 fc-list 命令查。如果 findFont() 返回 null,十有八九是名称写岔了。
其他几个踩过的坑:用了提取出来的 .ttf 还是乱码,多半是这个子字体本身就不包含中文,用 FontForge 看下字符集就清楚了;字体加载失败多半是路径不对或者文件损坏,先把文件拷出来双击看系统能不能预览,能预览再排查代码路径。
整体上,能走系统字体就先走系统字体,省事。真要离线可控版本,再从 .ttc 拆 .ttf。两套方案都跑通之后,这块就再没卡住过。
记录一次排序 NPE 的排查和解决,顺便说下 IDEA 调试集合时 null 元素不显示的问题怎么调整。
记录 datetime 字段定义、插入、格式化查询以及 Java 端类型映射、时区等问题,避免线上踩坑。
还在为Java程序阻塞而烦恼?本文将带你轻松掌握CompletableFuture.runAsync,告别传统阻塞模式。通过直观的错误与正确代码对比,你将学会如何用简单的lambda表达式在新线程中运行无返回值任务。快速理解Thread.currentThread().getName()的验证机制,立即解锁高性能并发编程,让你的应用响应更快!
本文详细解析Aspose.PDF中加载本地TTF和TTC字体的全套解决方案。针对TTF文件,可便捷使用FontRepository.openFont()直接加载。而面对TTC文件,我们提供了两种策略:借助FontForge等工具提取TTF子字体,或利用系统已安装的TTC字体名称进行高效加载,并附带字体名称验证与常见问题解答,确保您的PDF字体显示无忧。