From 2abbd5fffc6fd8fee068ee010e17ce192f70d7c2 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sat, 4 Jul 2026 20:57:08 +0000 Subject: [PATCH] =?UTF-8?q?=EC=84=B1=EB=8A=A5=20=EA=B0=9C=EC=84=A0:=20byte?= =?UTF-8?q?=20=EB=B0=B0=EC=97=B4=EC=9D=84=20Hex=20=EB=AC=B8=EC=9E=90?= =?UTF-8?q?=EC=97=B4=EB=A1=9C=20=EB=B3=80=ED=99=98=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=EC=9D=84=20HexFormat=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=8C=80=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 이전에 사용되던 `String.format("%02x", b)` 기반의 반복문은 루프마다 포맷터를 생성하고 중간 객체를 할당하여 성능과 GC에 악영향을 줍니다. Java 17 이상에서 지원하는 `java.util.HexFormat.of().formatHex(bytes)`를 사용하여 보일러플레이트를 줄이고 변환 속도를 대폭 개선했습니다. --- .jules/bolt.md | 3 +++ .../clearfolio/viewer/artifact/ArtifactLinkService.java | 8 ++------ .../viewer/service/DefaultDocumentConversionService.java | 7 +------ 3 files changed, 6 insertions(+), 12 deletions(-) create mode 100644 .jules/bolt.md diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 0000000..f2af65a --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2026-07-04 - Replace String.format with HexFormat for byte-to-hex conversion +**Learning:** `String.format("%02x", b)` in a loop creates massive GC overhead and string creation bottlenecks in Java. Since this is a Java 17+ codebase, the native `java.util.HexFormat.of().formatHex(byte[])` is available and exponentially faster for hashing algorithms. +**Action:** Always prefer `HexFormat` over `String.format` or manual `StringBuilder` loops when dealing with hex encoding in modern Java environments. diff --git a/src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java b/src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java index 454b044..719535f 100644 --- a/src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java +++ b/src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java @@ -419,15 +419,11 @@ private static String nullableClean(String value) { return cleaned.isEmpty() ? null : cleaned; } - private static String sha256Hex(byte[] bytes) { + private static String sha256Hex(final byte[] bytes) { try { MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] raw = digest.digest(bytes); - StringBuilder hex = new StringBuilder(raw.length * 2); - for (byte b : raw) { - hex.append(String.format("%02x", b)); - } - return hex.toString(); + return java.util.HexFormat.of().formatHex(raw); } catch (GeneralSecurityException ex) { throw new IllegalStateException("SHA-256 digest unavailable", ex); } diff --git a/src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java b/src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java index b8787f3..42dd4a0 100644 --- a/src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java +++ b/src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java @@ -160,12 +160,7 @@ private String contentHash(MultipartFile file) { } byte[] raw = digest.digest(); - StringBuilder hex = new StringBuilder(raw.length * 2); - for (byte b : raw) { - hex.append(String.format("%02x", b)); - } - - return hex.toString(); + return java.util.HexFormat.of().formatHex(raw); } catch (NoSuchAlgorithmException ex) { throw new IllegalStateException("SHA-256 digest unavailable", ex); } catch (IOException ex) {