跳到主要內容

發表文章

目前顯示的是有「Java」標籤的文章

Java heap dump 分析流程

雖然 Java 現在已經有很強大的 GC (特別是Java 11後的 ZGC) Memory leak 依然是個 Java 開發者得了解的議題 Memory leak 並不只在寫出持續無法被回收的物件 若是段落內的流程正確,但設計時的尖峰使用量估計錯誤,也可能讓 JVM 運行時碰到 OOM 了解記憶體分析的流程才能將架構調整得更合適

Java 實現民國年日期轉換

不知道大家現在還有沒有接到民國年轉換的需求 滿久以前偶爾會接到客戶寫信來問能不能做民國年的日期輸出或輸入 不過畢竟以前在處理上比較麻煩 最簡單的方式是請客戶分開資料欄位 分別產出民國跟西元年的資料,輸出時再依照需求組合出最終的字串 寫成常見Q&A之後就不大有需求信寄過來了

Mac版 Java 7 取得檔案 MIME type 的方式

現行 Java 取得檔案 MIME type的標準方式是透過 Files.probeContentType(Path path) 取得 最近處理同事回報的問題才發現這個方式在Mac版的 Java 7 有bug 官方錯誤列表: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=7133484 而且應該只會修正Java 8以後的版本 目前測試改用 URLConnection.guessContentTypeFromName(String fileNmae) 也是一種可行的方式 如果MIME type相關的程式有可能部署在 Mac環境的 Java 7的話,需要注意這個問題

Java Nashorn Engine 的 setTimeout 使用方式

之前想透過 Java 的 Nashron 執行 setTimeout 這個定時執行的 JavaScript 函式碰到問題 看起來 Nashorn 並沒有實作關於非同步的 JavaScript 機制 我並沒有花太多時間查閱相關規格,只能猜想也許他鼓勵設計者使用 Java 的 async 機制 不過有時候需要執行的JavaScript Code 沒辦法排除 setTimeout 而改寫成 Java code 查到的相容寫法如下: var setTimeout, clearTimeout, setInterval, clearInterval; (function () {     var timer = new java.util.Timer();     var counter = 1;     var ids = {};     setTimeout = function (fn,delay) {         var id = counter++;         ids[id] = new JavaAdapter(java.util.TimerTask,{run: fn});         timer.schedule(ids[id],delay);         return id;     }     clearTimeout = function (id) {         ids[id].cancel();         timer.purge();         delete ids[id];     }     setInterval = function (fn,delay) {         var id =...

工具庫 - 自訂 Java BBCode Parser

BBCode 是常在論壇還是一些輕量級應用使用的標籤 他在實際執行時會從 [b]test[/b] 這樣的標籤轉譯成 HTML 標籤 <b>test</b> 開放讓使用者自行撰寫 HTML 內容時,容易有撰寫錯誤或XSS安全性問題 所以使用這種限定規格的標籤,對使用者來說是比較容易的,對網站方也是相對好處理的 不過在搜尋既有的 Solutions 時發現多數都是 JavaScript 用的 Library Java使用者最常被推薦的可能是  kefirbb ,只是查看了規格後我是不太想使用 因為我不需要其他的標籤轉換功能,例如 Markdown 之類的 我也不想維護一個並不是一目瞭然的格式轉換用的 XML,需要加入或修改標籤時會有困難 滿多人會選擇自行寫簡單的 regular expression 轉換 不過幾乎網路上查到的 pattern 都沒法處理好巢狀(nested) BBCode 結構 以及新的標籤要對應不同的 regular expression,我也覺得是一種負擔 後來我看到了 Extendible-BBCode-Parser  這個JavaScript Library 結構上我覺得不錯 能有彈性的新增、修改標籤行為,也能確實處理好 nested BBCode 所以動手改寫了個 Java 的版本 目前調整到我覺得還可以的程度 改寫時我就只專注在我需要的部分,一些錯誤偵測我覺得沒必要就拿掉了 程式碼的長度覺得不適合整個貼上來,所以不貼code改貼 程式碼 Github 連結 跟參考的library一樣開放隨意修改、發佈 之前我對於 regular expression 大概就是基礎使用的程度 程式裡的那些 pattern 我也沒懂到可以說出什麼詳細教學 一些處理細節也是邊刻邊體會,從這次經驗學到了些東西,感謝原 Project 提供的各種想法

自動化重啟 Java Process

有些狀況下會碰到需要關閉 Java process 的狀況 不管是不可預期的,例如 OOM 導致 process crash 或是可預期的狀況,例如需要 Java程式、設定檔更新,而在系統內用 System.exit(0); 通常我們都會需要馬上再重開 Java process,將處理流程自動化會方便得多 Linux  bash 示範   JPID=0   while [ $JPID-eq 0 ]   do     eval "(java ...)"   # eval your own java process.     JPID=$?       # set PID to status.   done 用個迴圈監聽PID是否存在 Windows batch 寫法也是基於同樣概念 :exeLoop set JPID=-1 for /F "tokens=1" %%i in ('jps -lv ^| find "%MAINCLASS%"') do ( set JPID=%%i ) if %JPID%==-1 ( echo %_EXECJAVA% %JAVA_OPTS% -classpath "%CLASSPATH%" -.... %MAINCLASS% :: execute your own java process. ping 127.0.0.1 -n 2 -w 1000 > nul     :: wait for 2 seconds before next loop. ) goto exeLoop

Java 輸出 Exception 訊息到指定物件

Java 的 Exception 訊息預設會輸出到 Java Console 如果要將訊息另外紀錄在指定的文字檔案,可以採取的作法有兩種 1. 在作業系統下指令將 Java process 的輸出存到指定的文字檔 例如 Linux 環境下 eval \"$_RUNJAVA\" $JAVA_OPTS \ -classpath \"$CLASSPATH\"  >> "/log/err.txt" 2>&1 p.s.  上述的Java相關執行跟參數都是用另外指定的參數,所以請不要直接照抄 2. 將 Exception 存到 String 物件後,再另外用這個 String 做後續處理 StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); String errMsg = e.getMessage() + "\r\n " + sw.toString();

Java JavaScriptEngine Nashorn 設定 Date Instance 預設時間

Java 的 JavaScriptEngine 的時間會依照 Java 程式所在的環境時間、設定的時區為準 所以執行 JavaScript code 的 new Date(),取得的時間也會跟環境時間相同 我這次的需求是希望 new Date 取得的時間是客戶瀏覽器端的時間,而不是Server本地時間 讓運算結果更貼近客戶用瀏覽器取得的結果 查過了 ScriptEngine 的 Source code,他並沒有公開的方法可以設定 Instance 的時間 底層的 native date 型別的時間其實是使用 Java 的 System.currentTimeMillis(); 似乎是沒有插手的空間了? 不過好在 JavaScript 的特色就是彈性大 手動 override 掉 Date function 也可以解決 var timeMilliseconds = 1447739048291;   // millisecond is passed from client side. var d = new Date(timeMilliseconds),      _ODATE = Date; Date = function (a1, a2, a3, a4, a5, a6, a7) {     if (arguments.length === 0) {         return d;     } else if (arguments.length === 1) {         return new _ODATE(a1);     } else {         a3 = a3 || 0;         a4 = a4 || 0;         a5 = a5 || 0;         a6 = a6 || 0;...

Java 8 JavaScript Engine 引入 Java Class 的方法變更

Java 8 使用了新的JavaScript Engine "Nashorn" 使用上的一些方式跟過去不太一樣 在跑程式碼時發現了過去版本用來引入 Java class 的importClass、importPackage會跳Exception 看了 Open JDK的回報 ScriptEngine throws exception when evaluating importClass and importPackage Nashorn 採用了不一樣的方式引入 Java class,如果要維持相容性 可以在 JavaScript Engine 建立後執行這段程式碼 try { engine.eval("try {load('nashorn:mozilla_compat.js');} catch (e) {}"); } catch (ScriptException e) {} 因為用try catch包起來,所以如果Rhino讀到這段丟 Exception 會被包起來 這樣 Nashorn 也可以執行過去跑在 Java 上的有引入 Java class 的 JavaScript Code了 至於 Nashorn 的正式引入 Java class 用法看到 這篇文章 會是 var BigDecimal = Java.type('java.math.BigDecimal'); function calculate(amount, percentage) {    var result = new BigDecimal(amount).multiply(       new BigDecimal(percentage)).divide(          new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_EVEN);    return result.toPlainString(); } 型別會作為一個物件產生,這樣也比較符合 JavaScript 中的做法

Java - 使用 JavaScript Engine 在後端執行 JavaScript

這篇是想寫好一段時間了 最近剛好有需求做了滿完整的應用,剛好可以拿出來當示範 Java的JavaScript engine在現在前端開發的需求越來越多的情況下,活躍的場合更多了 通常在以下狀況,你可以考慮使用JavaScript Engine 1.你想在前端使用Java的物件、類別或方法 2.前端複雜的邏輯需要在後端實現 當然你也可以將前端的運算結果用JavaScript engine傳送給後端 不過我想這個需求,使用browser request傳遞前端運算成果到後端做起來會簡單很多 這次我的實作目的是需要將一段前端邏輯拉到後端實作 目的程式最初是為了前端的功能實作,儲存資料的方式也是JSON 最後會compile成一段在JavaScript執行的code 不過有時候變化就是那麼突然(咦),因為客戶的需求及安全性考慮需要在後端使用這個功能 這次乾脆讓他在後端以JavaScript的方式省掉重新設計邏輯的麻煩 程式碼如下:

Java 8 Nashorn ArrayIndexOutOfBoundsException

雖然有一段時間沒有發文 不過其實我都還是有寫些草稿,只是一直沒有完整的時間加筆 今天趁這個問題還在時效內,貼出來充版面XD 今天碰到的問題是在Java的scripting engine上跑字串實字(literal notation)會碰到  ArrayIndexOutOfBoundsException 追蹤原因後才發現客戶端使用了JDK8,難怪會有這個跟測試端不同的狀況 如同大家所知,在JDK8後Oracle揮別了過去使用的Rhino,改用新開發的Nashorn 這個例外很難不聯想到新引擎的bug 查了下果然看到類似的 問題 然後這是官方的回覆 I can reproduce the problem with 8u20, however it seems to be fixed in  JDK 9 and JDK8u40. You can download a preview release of 8u40 here: https://jdk8.java.net/download.html 這個問題推測會發生在使用數字做為JavaScript物件的屬性時 目前測試還有一種暫時的解法 就是不使用字串實字建立JavaScript物件,而是用Object的Constructor建立 也就是 var obj = {} -> var obj = new Object() 目前看起來可行,當然不保證不會觸發其他的問題 也許new Object()的實作方式是使用Java的Object,所以不會有這問題 猜測歸猜測,如果沒辦法等官方的修正,也許還是可以試試看這方法

Windows環境 Java 8 update 後產生的 "Could not find Java SE Runtime Environment"

最近幾次更新Java 8時多少會碰到一些問題,實在很想問Oracle團隊 "你們累了嗎?"... 很明顯最近幾次是變更過往使用的路徑配置,但在 registry key 的部分沒改到 這次升到 Java 8 update20 就發現 jre 的目錄名稱為 jre1.8.0_20,而不是過往使用的 jre8的命名 升級後到 console 可以發現 java 的指令無法使用 這一連串的完整錯誤訊息是 Error: opening registry key 'Software\JavaSoft\Java Runtime Environment' Error: could not find java.dll Error: Could not find Java SE Runtime Environment. 解決方式會需要修改registry key 首先打開windows的命令提示字元(win8.1的快捷方式是Fn+R然後搜尋cmd) 輸入regedit 打開 Windows 的註冊編輯程式 找到 HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment 先在這個機碼裡面新增字串 CurrentVersion ,數值設定為 1.8 接著新增機碼 HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment\1.8 在裡面新增新增字串 JavaHome,數值設定為你現在的 jre8 的路徑 修改完後到命令提示字元試試 java -version 這指令是否已經生效

Eclipse 使用 Ant 產生 jar 檔

這篇只做簡單介紹,不做Ant的教學 Ant 是Apache基金會底下的其中一個自動化工具專案 特別是 Java 使用者應該都會聽過這個工具 Eclipse 已經將這個工具整合為其內部功能之一,所以我們可以透過Eclipse的介面來執行

Java 物件容器筆記

在Java裡,對於物件的收集、處理有兩種不同的概念 1.Collection -    收集物件並形成一個具有相同處理規範的物件集合    List 在收集物件時會記錄其索引順序,所以可藉由索引取回物件    Set 會過濾掉已經收集過的物件,形成一組不重複的物件集合    Queue 以佇列的形式收集物件,對於佇列兩端的物件有較方便的操作 2.Map -    Map是一群成對的key-value物件,讓使用者可以透過另外一個物件查詢目標值    對於物件集合,提供了搜尋的方便性

Java 零碎知識筆記

1.Arrays.copyof(arg1, arg2)是一種淺層複製(shallow copy)的方法    參數1是欲複製的陣列,參數2則是新陣列的長度    因為JVM不會知道Array裡的物件到底有哪些類別及那些屬性    所以若想進行深層複製,則需要自己實作 2.引用static方法的宣告方式需要完全指名路徑,如:import java.lang.System.out 3.Java的繼承原理是即使是private宣告的成員也會被繼承   但僅有父類別的方法能存取它 4.重新定義equals()的範例    public class Cat{        public  boolean equals(Object other){         if(this == other){            return true;         //參考指向同一物件當然是相同 } if(!(Other instanceof Cat)){            return false;       //如果不由相同類別宣告自然不會相同 } Cat cat = (Cat) other; if(...){                 //以下開始比較Cat類別中的類別成員值是否相同            ....         }        }    }

Java 建構式筆記

建構式之前若有想先執行的流程可以使用{} 以區域概念保留一塊優先執行的區域 Class Demo{     {           ...    //do something       }     public Demo(){            ....     } } 若是在這一塊優先執行的區域前加上static敘述 static{   ...     //do something    } 則會讓JVM在載入這個class的bytecode後立刻執行區塊內的程式碼 JDBC的class.forName()就是這樣的處理