quick ways to initialize a list of numbers or strings in java

Java 快速建立整數與字串清單的寫法

在 Java 中,建立 List<Integer>List<String> 是非常常見的需求。 以下依照不同 JDK 版本,整理出幾種快速建立可修改(modifiable) 清單的寫法,可依個人習慣彈性使用。

1️⃣ JDK 5(2004)起支援的寫法

自 JDK 5 起,Java 引入了 泛型(Generics)自動封裝(Autoboxing),因此可以直接將 int 自動轉為 Integer


  Integer[] intArray = {1, 2, 3};
  String[]  strArray = {"A", "B", "C"};

  List<Integer> ints =
    new ArrayList<Integer>(Arrays.asList(intArray));

  List<String> strings =
    new ArrayList<String>(Arrays.asList(strArray));
  
✅ 適用於舊版系統(JDK 5 / 6)
✅ 清楚明確,但型別宣告較冗長

2️⃣ JDK 7(2011)起支援的寫法(鑽石運算子)

JDK 7 引入了 鑽石運算子(<>, 可讓編譯器自動推斷泛型型別,使程式碼更精簡。


  List<Integer> ints =
    new ArrayList<>(Arrays.asList(1, 2, 3));

  List<String> strings =
    new ArrayList<>(Arrays.asList("A", "B"));
  
✅ 語法更簡潔
✅ 仍然回傳可修改的 ArrayList

3️⃣ Java 9(2017)起支援的寫法(搭配 List.of

Java 9 引入了 List.of() 作為集合工廠方法, 可快速建立不可修改的清單。 若實務上仍需要可修改的清單,可再包裝成 ArrayList


  List<Integer> ints =
    new ArrayList<>(List.of(1, 2, 3));

  List<String> strings =
    new ArrayList<>(List.of("A", "B"));
  
✅ 語意清楚、現代化寫法
⚠️ List.of() 本身不可修改,需額外包裝

✅ 小結

  • JDK 5+:可使用泛型與自動封裝
  • JDK 7+:可使用鑽石運算子,讓程式碼更乾淨
  • Java 9+:可搭配 List.of() 撰寫更語意化的程式碼

實務上建議:
👉 需要可修改清單 ⇒ 使用 new ArrayList<>(...)
👉 元素固定不變 ⇒ 直接使用 List.of()

compare java wait/notify synchronization with lock or condition in java.util.concurrent (juc)

為什麼 Java 的 wait/notify 逐漸被新 API 取代?

在 Java 的演進過程中,雖然 Object.wait()Object.notify() 仍存在於核心庫中,但在現代開發場景,java.util.concurrent (JUC) 提供的 LockCondition 已成為主流。以下是三大核心取代原因:

1. 靈活性與精確控制 (Multiple Conditions)

這是最關鍵的進步。舊有機制中,每個物件僅有一個「等待集」。

  • 舊機制: 生產者與消費者共用同一個等待隊列。呼叫 notify() 無法指定喚醒誰,常被迫改用 notifyAll(),導致驚群效應 (Thundering Herd)
  • 新機制 (Condition): 一個鎖可建立多個條件物件(如 notFull, notEmpty)。生產者只需喚醒消費者,反之亦然,效能大幅提升。

2. 安全性與健壯性 (Robustness)

新 API 解決了許多語法上的僵化問題:

特性 Object.wait/notify JUC Condition
鎖的依賴 強烈耦合 synchronized 配合 ReentrantLock,更靈活
中斷響應 僅支援基本中斷 支援不可中斷的等待 (awaitUninterruptibly)
超時控制 毫秒級 精確至奈米級 (nanoseconds)

3. 功能擴展性 (Advanced Features)

ReentrantLock 提供了舊機制無法達成的進階功能:

公平性 (Fairness): 新 API 支援公平鎖設定,確保等待最久的執行緒優先獲取資源。
非阻塞嘗試: 透過 tryLock(),執行緒可以在拿不到鎖時立即返回,避免死等。
總結:除非是極簡的同步邏輯,否則在現代 Java 開發中,ReentrantLock + Condition 是更安全、高效的選擇。

choose which S3 object ownership?

S3 Object Ownership 兩種模式差異

Amazon S3 服務全名為 簡單儲存服務 (Simple Storage Service),可支援存取放置於AWS公有雲的檔案,其服務類似 Google Drive 或 Microsoft OneDrive 的網碟功能。S3 儲存容器稱為水桶,儲存的檔案稱為物件。

建立S3水桶時,須決定上傳到水桶的物件,其擁有者將自動歸屬於誰,稱為物件擁有權(Object Ownership)設定。只有物件的擁有者才能設定物件的存取權。這裡簡單介紹兩種設定模式的差異:

🔒 模式一:ACL disabled(recommended)

所有物件都由 Bucket 擁有者持有,不論是誰上傳。ACL 完全被停用,不能再用 ACL 來授權。存取控制只能透過 IAM Policy 或 Bucket Policy 來設定。

優點:集中管理,避免跨帳號物件所有權混亂。

最佳實務:AWS 建議使用這種模式,因為更安全、更容易維護。

🔑 模式二:ACLs enabled

物件可能由上傳者帳號持有,而不是 Bucket 擁有者。存取控制可以透過 ACL(物件或 Bucket 層級)來設定。Bucket Policy 仍然可以使用,但 ACL 會一起參與判斷。

用途:適合跨帳號上傳的特殊情境,例如合作夥伴需要保有自己上傳檔案的所有權。

缺點:管理較複雜,容易造成權限混亂。

⚡ 簡單比較
模式	     物件擁有者	                存取控制方式	      AWS 建議
ACL Disabled Bucket 擁有者	        Policy(IAM / Bucket)✅ 建議
ACL Enabled  上傳者帳號可能成為物件擁有者  ACL + Policy	      僅限特殊需求

✍️ 結語

如果你的環境需要簡單、集中、安全的存取管理,選擇 ACL Disabled(Bucket owner enforced) 是最佳做法。 只有在跨帳號物件所有權的特殊需求下,才需要考慮 ACL Enabled

註: S3 權限管理機制比較:ACL vs. 水桶政策

功能特性 S3 ACL (存取控制清單),舊版 水桶政策 (Bucket Policy),新版
物件所有權 預設由「上傳者」擁有物件,即使上傳者不是水桶擁有者。 由「水桶擁有者」自動擁有水桶內的所有物件。
設定格式 XML 格式。 JSON 格式。
控制粒度 可針對「單一物件」進行微調。 針對整個水桶或特定「前綴 (Prefix/資料夾)」進行管理。
權限複雜度 僅限基本權限(讀取、寫入、完全控制),不支援「拒絕 (Deny)」。 支援複雜條件(IP 限制、MFA、特定時間、明確拒絕等)。
稽核便利性 低。必須逐一檢查每個物件的 ACL 才能得知誰有存取權。 高。只需查看一個 JSON 文件即可瞭解全域權限。
AWS 建議實務 不建議使用(除了特定日誌寫入需求)。 強烈建議使用(最佳實務)。

how to deal with metric scale inconsistency in topn recommendation evaluation

🎯 推薦系統一般會回傳前 N 個排名的物品清單給用戶,稱為 Top‑N 推薦。 遇到推薦模型須要訓練及評估時,習慣先蒐集用戶與物品的互動資料,再將資料拆分成沒有重疊的訓練集及測試集。 模型在訓練時只看得到訓練集,評估時則拿測試集作為驗證的標準答案,以免作弊。

通常,在評估推薦模型時,和一般機器學習的模型評估不同,會採用逐用戶等比例切割 (userwise stratified split) 評估法。 即針對每個用戶的喜好物品,等比例拆分成訓練集及測試集,請模型利用全體訓練集作出該用戶的 Top‑N 推薦,然後利用其個人測試集作核對,計算該用戶的得分指標。 因為模型未看過測試集,所以最後全體用戶的指標平均值就是模型的客觀表現,可供比較之用。

上述作法在實際計算得分指標時,常遇到測試集數量和推薦數量 N 不匹配,造成得分指標尺規不一致的困擾。以下進行問題,原理,及解法說明。

❓ 問題介紹

逐用戶等比例切割 的設定下,每位用戶的測試集互動數量不一樣。 當使用固定的 Top‑N 推薦清單做評估時,就會出現「測試集大小與 Top‑N 回傳數量不匹配」的情況:

  • 👤 輕度互動的用戶:測試集互動數 |Rᵤ| < N
  • 👥 重度互動的用戶:測試集互動數 |Rᵤ| > N

這會讓 回傳數量 N 的精確率 Precision@N,及回傳數量 N 的召回率 Recall@N 產生尺規上限受限的現象, 影響不同用戶之間評比的尺規公平性。

🔍 原理說明(為什麼會不公平)

若使用 Top‑N 評估,指標的分母固定或依用戶而變:

  • Precision@N = 命中數 / N,其分母固定為 N, 輕度互動用戶的精確率最大值會受此尺規「天花板」限制,達不到 1.0。
  • Recall@N = 命中數 / |Rᵤ|,其分母為 |Rᵤ|, 重度互動用戶的召回率最大值會受此尺規「天花板」限制,達不到 1.0。

這並非「計算錯誤」,而是 Top‑N 回傳量的本質所導致的評估上限不一致。

相比之下,✨正規化打折累積增益 NDCG@N 指標會以用戶理想排序的 理想打折累積增益 IDCG 進行正規化, 而 IDCG 的長度是 min(|Rᵤ|, N)。因此每位用戶都能達到 1.0 的尺規滿分, 不會因為測試集大小不同而被系統性壓低。

💡 實務解法

以下是最常見的三種解決做法:

  1. ✅ 接受個別用戶的指標尺規上限不同:只要所有模型都在相同的尺規限制下比較,排名仍有參考價值。 因為各模型可在相同受限指標尺規範圍內求好表現,所以不影響依據指標平均值所作的模型排名比較。
  2. 📋 粗糙解法:改用留1筆 Leave‑One‑Out(LOO)分割法,每位用戶只保留一筆測試互動,再搭配 命中率 Hit Rate (HR@N) = 命中數 指標作評估, 其值為 0 或 1。
  3. ⭐ 精細解法:改以 NDCG@N 作為主指標,並輔以 Precision/Recall/HR, 讓輕重度互動的用戶都能公平比較。

start versus restart for docker containers

Docker start vs restart:快速掌握差異

Docker 是個方便的服務部署工具,可快速安裝執行伺服軟體,供瀏覽器等前台使用。當用戶從 docker 映像檔建立 (create) 及啟動 (start) 容器時,容器將分別處於 巳建立 (created)執行 (running) 狀態。然後,遇到執行意外出錯 或 管理者故意下停止指令 (docker stop) 時,容器將進入退出 (exited) 狀態。

處於退出狀態的容器,因行程退出,將喪失記憶體狀態,但仍保有原來的可寫層 (writable layer) ,即儲存體狀態。此時,兩種指令 docker start 與 docker restart 都能讓既有容器,從現有可寫層狀態,再跑起來,效果完全一樣。以下用表格整理說明兩指令適用時機之差異。

1. 指令行為比較

指令 行為說明 適用狀態
docker start 啟動 巳建立 (created)退出 (exited) 的既有容器,直接執行其進入點命令 (entrypoint command) created / exited
docker restart 同上,但遇到執行狀態的容器會先讓其 stop,再 start created / running / exited

2. 執行期影響比較

項目 start restart
送 SIGTERM / SIGKILL
PID 改變
記憶體狀態重置
中斷連線
停機時間短暫

3. docker restart 的清理範圍

區域 是否清理
In-memory data
Processes / threads
Open sockets
TCP connections
Writable filesystem
Volumes
Env / config
Image

4. 結論:適用性與效果

docker startdocker restart 兩個指令目的都在不放棄既有容器的可寫層之下,以新記憶體,執行容器的服務。在容器處於 退出 狀態時,兩者效果完全相同,都會重新啟動容器主行程,重新分配記憶體,並執行 entrypoint command。 其適用時機摘要如下表。

適用情境 效果
容器正常退出,要再跑一次docker start
就現有可寫層,啟動既有容器
程式卡住、連線異常docker restart
保留可寫層,重新啟動既有容器
組態設定或資料壞掉docker run
放棄可寫層,重新建立啟動新容器

Linked Lists from C to Java

C Pointer Concepts in Java」一文提到 Java 沒有指標型別 (pointer type) ,但有參照型別 (reference type) 的設計。在遇到須要處理鏈結清單 (linked list)、圖形 (graph) 等資料結構時,Java 如何透過參照型別,仍能達成類似的效果。本文將以「鏈結清單」為例,分別用 C 與 Java 實作,說明兩者的差異與對應。


🔹 C 語言:使用指標建立鏈結清單

/*
   1 -> 2 -> 3 NULL
*/
#include <stdio.h>
#include <stdlib.h>

// 定義節點結構
typedef struct Node {
    int data;  // 資料
    struct Node* next;  // 下一節點指標
} Node;

int main() {
    // 建立三個節點
    Node* head = (Node*)malloc(sizeof(Node));
    Node* second = (Node*)malloc(sizeof(Node));
    Node* third = (Node*)malloc(sizeof(Node));

    // 給值與連結
    head->data = 1;
    head->next = second;

    second->data = 2;
    second->next = third;

    third->data = 3;
    third->next = NULL;

    // 印出鏈結清單
    Node* current = head;
    while (current != NULL) {
        printf("%d -> ", current->data);
        current = current->next;
    }
    printf("NULL\n");

    return 0;
}
    其中,
  • Node* 是指標變數,指向記憶體中的節點。
  • 使用 malloc 配置記憶體,並用 -> 操作指標指向的內容。
  • 每個節點透過 next 指向下一個節點,形成鏈結。

🔹 Java 語言:使用參照建立鏈結清單

/*
   1 -> 2 -> 3 null
*/

// 定義節點結構
class Node {
    int data; // 資料
    Node next;  // 下一節點參照

    Node(int data) {
        this.data = data;
        this.next = null;
    }
}

public class LinkedListDemo {
    public static void main(String[] args) {
        // 建立三個節點
        Node head = new Node(1);
        Node second = new Node(2);
        Node third = new Node(3);

        // 給值與連結
        head.next = second;
        second.next = third;

        // 印出鏈結清單
        Node current = head;
        while (current != null) {
            System.out.print(current.data + " -> ");
            current = current.next;
        }
        System.out.println("null");
    }
}
    其中,
  • Node 是一個類別,變數如 headsecond 是參照變數,指向物件。
  • 使用 new 建立物件,並透過 . 操作物件的屬性。
  • 雖然語法上沒有 *&,但物件的參照本質上就像 C 的指標。

🔄 對照總結:C 指標 vs Java 參照

概念C 語言Java 語言
記憶體操作明確使用 *&隱含於物件參照
記憶體配置mallocnew
節點連結指標指向下一節點物件參照指向下一節點
安全性容易出現記憶體錯誤自動垃圾回收記憶體管理 (GC)

以上說明 Java 雖然沒有指標型別,但仍能透過「參照型別」的設計,實現如鏈結清單這類需要動態記憶體與節點連結的資料結構。希望對於從 C 過渡到 Java 的學習者有幫助。

Installing Code::Blocks on Windows for APCS Preparation

APCS 為大學程式設計先修檢測 (Advanced Placement Computer Science),其檢測等級可供大學個人申請入學之用。各電腦相關科系APCS組都明訂要求的檢測等級,須符合其門檻才具備申請資格。其中,針對 C 及 C++ 程式檢測,考場提供 Linux 環境的輕量級 Code::Blocks 整合開發環境 (IDE) 供程式撰寫及執行之用。

考生若想在家裏 Windows 作業系統上熟悉 Code::Blocks,一種方法是下載考場 Linux 環境 .iso 檔,安裝 VirtualBox 虛擬機軟體,將 Linux 虛擬機跑起來,使用其桌面安裝好的Code::Blocks。另一種方法則是直接在 Windows 自行安裝 Code::Blocks。

本文將介紹後者,如何在 Windows 系統上安裝 Code::Blocks,並參考考場 Linux 虛擬機中的 Code::Blocks 進行設定,以獲得和考場 Linux 環境一樣的 Code::Blocks 寫程式體驗。


📥 Windows安裝 Code::Blocks

 🆚不推薦新版本:Code::Blocks 25.03 (含 MinGW 編譯器)

  • 下載連結:https://www.codeblocks.org/downloads/binaries/
    •   Binary releases
    •     Windows XP / Vista / 7 / 8.x /10
    •       Microsoft Windows (64 bit, default)
    • codeblocks-25.03mingw-setup.exe
  • 適用系統:Windows XP / Vista / 7 / 8.x / 10(64 位元)

     本版本內建 MinGW 編譯器,安裝後即可開始編寫與編譯 C/C++ 程式。但因為安裝時易受某些防毒軟體拒絕,若心有疑慮,不想關閉防毒軟體,建議不要安裝。

 ✅ 推薦舊版:Code::Blocks 20.03  (含 MinGW 編譯器)

      本版本也內建 MinGW 編譯器,安裝後即可開始編寫與編譯 C/C++ 程式。雖然是舊版,但目前為考場安裝版本,且不會受防毒軟體拒絕,故建議安裝。

⚙️ 設定編譯器支援 C++17 / C17

以下依據考場 Linux 虛擬機安裝組態,設定Windows Code::Blocks 20.03 的編譯器選項:

1️⃣ 開啟 Code::Blocks,進入:

Settings → Compiler...

2️⃣ 在「Global compiler settings」中,確認選擇的編譯器為:

Selected compiler: GNU GCC Compiler (default)

3️⃣ 點選「Compiler settings」→「Compiler Flags」,勾選以下選項,點選OK:

  • ✅  Have g++ follow the C++17 ISO C++ language standard [-std=c++17]
  • Have gcc follow the 2017 ISO C language standard [-std=c17]
  • Static linking [-static]
註: 以下為考場提供 .iso 檔安裝的 Linux Code::Blocks 20.03 組態
  • Have gcc follow the 2017 ISO C language standard [-std=c17]
  • Have gcc follow the C++17 ISO C++ language standard [-std=c++17]
  • Static linking [-static]


Building a Lightweight Streamlit Client for Local Ollama LLM Interaction

Ollama 提供端點串接服務,可由程式管理及使用本地大語言模型(LLM, Large Language Model)。 以下程式碼展示如何以 Streamlit 套件,建立一個輕量級的網頁介面,供呼叫本地端安裝的 Ollama 大語言模型。 Ollama 預設的服務端點為 http://localhost:11434。 使用者透過簡單的網頁操作,即可輸入提示詞(prompt),即時獲得模型回應。 此應用支援模型選擇、選字機率均化溫度(temperature)、選字累加機率門檻值(top_p)、問答最大符號數(max_tokens)等參數調整,並允許限定特定使用者(如 "john")。 Ollama Streamlit為一個實用的範例,適合想要快速整合本地 LLM ,建立互動式介面的開發者。

######################################
#  ollama_client_streamlit.py
#   an streamlit client to call ollama LLMs.
#
#   # python 3.7.7 above recommended
#   > conda activate your_streamlit_environment
#   > streamlit run ollama_client_streamlit.py --server.port 8080
#
#   http://localhost:8080?name=john
#
# Reference:
#   GitHub: Ollama API Documentation
#
import streamlit as st
import requests
import time
import json

###################################
# Parameters for the Streamlit App
baseurl = 'http://localhost:11434'
generate_url = baseurl + '/api/generate'
tags_url = baseurl + '/api/tags'
# only names in pass_list are allowed to use LLM
pass_name_list = ["john"]   
default_prompt = 'Where is the capital of Japan?'
# api_key is optional for endpoints with bearer authentication
api_key = ''

# returns a list of llm names installed in ollama
def get_ollama_models():
    """Fetches available models from the Ollama API and returns a list."""
    ##url = "http://localhost:11434/api/tags"  # Ollama API endpoint
    try:
        headers={'Authorization': f'Bearer {api_key}'}
        response = requests.get(tags_url, headers=headers)
        
        # Raises an error for HTTP failures
        response.raise_for_status()
        data = response.json()

        # Extract model names
        return [model["name"] for model in data.get("models", [])]  
    except requests.exceptions.RequestException as e:
        print(f"Error fetching models: {e}")
        return []


# Calls /api/generate to request LLM in stream=true mode
#   model: ollama installed llm
#   temperature: 0 ~ 1 (decide how creative the answer is generated)
#   top_p: 0 ~ 1 (decide how many most probable words to select)
#   max_tokens: 0 ~ 2048 tokens
def generate_stream(prompt, model, temperature=0.7, top_p=0.95, max_tokens=1024):
    args = {
        'prompt': prompt,
        'model': model,
        'options': {
            'temperature': temperature,
            'top_p': top_p,
            'max_tokens': max_tokens},
        'stream': True
    }

    headers = {'Authorization': f'Bearer {api_key}'}
    r = requests.post(generate_url, headers=headers, json=args, stream=True)
    if r.status_code == 200:
    # {"model":"gemma3:12b-it-qat",
    #  "created_at":"2025-05-24T09:18:43.944815912Z",
    #  "response":"The","done":false}
        # print("Request successful!")
        # with requests.post(url, headers=headers, 
        #    data=json.dumps(data), stream=True) as response:
        for line in r.iter_lines():
            if line:
                try:
                    chunk = json.loads(line.decode("utf-8"))
                    message = chunk.get("response", {})
                    # print(message)
                    yield message
                except json.JSONDecodeError:
                    continue

        # message = r.json()['response']
    else:
        message = f"Error: {r.status_code}, Message: {r.text}"

    # response_json = response.json()
    # message = response_json['response']

    yield message


#  no cache resource is needed with ollama endpoints
@st.cache_resource
def _load():
    return

#  calls generate_stream() to collect stream chunk response 
#    in _result.markdown(full_response)
@st.cache_data(ttl='1d')  # cache _result for one day
def _generate(prompt, model, temperature=0.7, top_p=0.95, max_tokens=1024):
    _result = st.empty()
    full_response = ''

    start = time.time()
    for chunk in generate_stream(prompt, model, temperature, top_p, max_tokens):
        full_response += chunk
        _result.markdown(full_response)
        # st.write_stream(response)
    end = time.time()

    st.write(f"generate text in {end - start:.3f} seconds\n\n")
    # return response_placeholder


start = time.time()
_load()
end = time.time()

#############
# filter user
# only names in pass_name_list are allowed to use the app
params = st.query_params
name = params.get("name", "")
if name in pass_name_list:
    result = f"Hello, {name}!"
else:
    #result = "Unsupported user"
    st.write(f"Sorry, you are not supported user.")
    exit(0)

###############
# Streamlit UI
st.sidebar.write(f"Hello, {name}!")

# title for the web page
st.title("Ollama LLM Demo ")

# let sliders be located in left hand side of ui
# slider for temperature
temperature = st.sidebar.slider("temperature", 0.0, 1.0, 0.7, 0.01)

# slider for top_p
top_p = st.sidebar.slider("top_p", 0.0, 1.0, 0.95, 0.01)

# slider for max_tokens
max_tokens = st.sidebar.slider("max_tokens", 0, 2048, 1024, 1)

# selectbox for model_engine
models = get_ollama_models()
#print(models)  # ["llama3.1", "gemma3:12b-it-qat"]
model_engine = st.sidebar.selectbox("model_engine", models)

# input text
prompt = st.text_area("Your Query for LLM", default_prompt)

# output area
_generate(prompt, model_engine, temperature, top_p, max_tokens)

how to install and use Jeddict AI Assistant on NetBeans IDE 23+

Jeddict AI Assistant 為適用於 NetBeans IDE 23 以上版本的插件,能夠連接大語言模型,協助編寫程式碼,大幅提升開發體驗,讓程式撰寫更輕鬆、更智慧。以下簡介其安裝方法及功能。

A.安裝與解除安裝

  • 安裝步驟:
    • 開啟 NetBeans IDE
    • 點選 Tools/Plugins/Available Plugins
    • 搜尋並安裝 Jeddict AI Assistant
    • 點選 Tools/Options/Jeddict AI Assistant
      Providers: OLLAMA,
      URL: http://localhost:11434,
      Model: qwen2.5-coder:7b
  • 解除安裝步驟:
    • 點選 Tools/Plugins/Installed
    • User Installed Plugins 下,選擇 Jeddict AI Assistant
    • 點擊解除作用 (Deactivate)解除安裝 (Uninstall)

B.主要功能與使用說明

Jeddict AI Assistant 提供了多種智慧功能,幫助提升程式碼品質與開發效率:

  1. 智慧程式碼補全

    (Smart Code Completion)
    • 用法: 在編輯程式碼時,按下 Ctrl+SpaceCtrl+Alt+Space 鍵,AI 會提供相關的程式碼建議。按下 Enter 鍵即可接受建議。
    • 說明: AI 會學習程式碼上下文,提供更精準的補全、變數和方法重命名,以及改進日誌訊息或註解的建議,大幅提高編碼效率。
  2. 行內提示

    (Inline Hint)
    • 用法: 在編輯程式碼行時,按下 Enter 鍵,AI Assistant 會直接在程式碼編輯器中顯示基於當前上下文的行內提示。再次按下 Enter 鍵即可確認並整合建議,或按下其他任意鍵取消。
    • 說明: 提供即時、上下文感知的建議,有效提升程式碼品質和效率,且不干擾開發流程。
  3. 為行內提示提供上下文

    (Providing Context to Inline Hint)
    • 用法:
      • 使用註解作為提示: 在程式碼中撰寫註解說明程式意圖,然後按 Enter 鍵。AI 會將註解和現有程式碼作為上下文。
      • 使用儲存的提示: 在設定中定義長提示,然後在編輯器中輸入 /prompt-id 並按 Enter 鍵來重複使用。
      • 即時擴展儲存的提示: 輸入 /{prompt-id} 加上額外上下文,AI 會同時處理儲存的提示和額外文字。
    • 說明: 可更精確地控制 AI 的建議,使其更符合當前的開發任務。
  4. 方法強化

    (Method Enhancement)
    • 用法: 反白顯示任何方法,然後點擊提示:"AI: Enhance the method"。
    • 說明: AI 會根據專案需求,改進方法的邏輯、結構或效率。
  5. Javadoc 創建與改進

    (Javadoc Creation & Improvement)
    • Javadoc 創建用法: 反白顯示任何類別、方法或介面,然後點擊提示:"AI: Create Javadoc using assistance"。
    • Javadoc 改進用法: 反白顯示任何類別、方法或介面中現有的 Javadoc 註解,然後點擊提示:"AI: Enhance existing Javadoc"。
    • 說明: AI 會自動生成符合程式碼上下文的 Javadoc,並提升其清晰度、準確性和符合最佳實踐。
  6. 變數命名建議

    (Variable Naming Suggestions)
    • 用法: 反白顯示任何變數或參數,然後點擊提示:"AI: Improve variable name using assistance"。
    • 說明: 自動建議更有意義且符合上下文的變數名稱,提升程式碼的可讀性和可維護性。
  7. 語法修正

    (Grammar Fixes)
    • 用法: 選擇任何字串文字 (例如註解、Javadoc 或其他文本),然後點擊提示:"AI: Fix grammar issues using assistance"。
    • 說明: 檢測並修正程式碼中註解、Javadoc 或其他文本內容的語法錯誤,確保文件專業且潤飾精良。
  8. 文本強化

    (Text Enhancement)
    • 用法: 選擇任何字串文字 (例如註解、文件或日誌訊息),然後點擊提示:"AI: Enhance text quality using assistance"。
    • 說明: 透過提供更簡潔、更有影響力的替代方案,提升文本內容的品質和可讀性。
  9. 程式碼行強化 (Code Line Enhancement)

    • 用法: 選擇任何單行程式碼片段,然後點擊提示:"AI: Enhance a single line of code"。
    • 說明: 建議單行程式碼的強化或最佳化,確保表達簡潔、高效和可維護。
  10. 學習類別

    (Learn about Class)
    • 用法: 反白顯示類別名稱,然後點擊提示:"AI: Learn about Class"。之後可以在聊天中繼續詢問特定問題。
    • 說明: 提供關於特定類別的深入見解和詳細解釋,包括其方法、屬性以及在專案中的用法。
  11. 生成測試案例

    (Generate Test Cases)
    • 用法: 反白顯示任何類別或方法,然後點擊提示:"AI: Generate Test for Class or Method"。
    • 說明: 根據 AI Assistant 提供的上下文提示,自動為類別或方法生成測試案例,簡化測試寫作流程。

C.AI 聊天功能

Jeddict AI Assistant 提供了多種上下文感知的 AI 聊天模式,可有效解決開發問題:

  1. 感知專案上下文的 AI 聊天

    (Project Context-Aware AI Chat)
    • 用法: 在專案開啟時,右鍵點擊專案並選擇 "AI Assistant" 以啟動 AI 聊天。
    • 說明: AI 聊天會考量整個專案的上下文,提供針對專案結構和組件的全面見解和支援。
  2. 感知 Java 套件與類別上下文的 AI 聊天

    (Java Packages & Classes Context-Aware AI Chat)
    • 用法: 選擇所需的套件或類別,右鍵點擊並選擇 "AI Assistant" 以開始聊天。
    • 說明: 針對特定的 Java 套件或類別與 AI 互動,獲得反映該套件或類別上下文的見解和建議。
  3. 編輯器提供各 Java 類別專屬的 AI 聊天

    (Tailored AI Chat for Individual Java Classes from Editor)
    • 用法: 在編輯器中開啟所需的 Java 類別,右鍵點擊並選擇 "AI Assistant" 以啟動專注於該類別的對話。
    • 說明: 針對單個 Java 類別與 AI Assistant 進行有針對性的討論,接收專門針對該類別的詳細分析和改進建議。
  4. 網頁開發上下文感知的 AI 聊天

    (Web Development Context-Aware AI Chat (HTML, CSS, JS, JSF))
    • 用法: 選擇 webapp 目錄或其任何子目錄,右鍵點擊並選擇 "AI Assistant"。
    • 說明: 與 AI 針對 HTML, CSS, JavaScript 和 JSF 等網頁應用程式組件進行交流,獲得針對網頁開發的上下文感知支援和建議。
  5. 通用 AI 聊天

    (General AI Chat (No Context Required))
    • 用法: 點擊頂部工具列上的 Jeddict 按鈕。
    • 說明: 無需程式碼或專案上下文即可使用 AI 聊天功能,適用於一般查詢或不與特定程式碼元素相關的討論,更具成本效益且速度更快。

D.其他實用功能

  1. 國際化支援

    (Internationalization Support)
    • 可透過在設定面板中設定 系統訊息 (System Message) 來配置 AI 以特定語言回應,例如使用 "Respond in French"。
    • 對於某些語言,可能需要使用相容的字體來正確呈現聊天視窗和編輯器中的文本。
  2. 支援 PlantUML 和 Markdown 支援

    (PlantUML and Markdown Support in Chat)
    • 現在可以直接在聊天視窗中查看和編輯 PlantUML 圖表和 Markdown 內容。當要求圖表或格式化文本時,會即時顯示,可以在提交前預覽和進行更改。
    • 原地編輯 (Edit in-place): 只需點擊圖表或 Markdown 區塊即可直接在聊天中編輯。
    • 請注意: 所做的任何更改不會發送給 AI,直到明確地複製並貼上更新的內容到輸入框並提交。
  3. AI 式提交訊息

    AI Commit Message
    • 用法: 右鍵點擊專案並選擇 "AI Commit Message" 以自動生成提交訊息。此選項僅在 Git 檢測到更改時可見。
    • 說明: 根據 Git 儲存庫中檢測到的差異生成有意義的提交訊息,簡化版本控制流程。
  4. AI式 SQL 聊天助理

    (SQL AI Chat Assistant)
    • 用法: 導航至 Services > Databases > Register DB in Apache NetBeans。右鍵點擊資料庫連接並選擇 "AI Assistant"。
    • 說明: 這將啟動 AI 聊天視窗,提供基於資料庫的上下文。AI 將在 SQL 編輯器中生成結果,能夠在同一個聊天視窗中利用 AI 進行 SQL 查詢的智慧行內補全。
  5. AI 式 SQL 行內補全

    (SQL Inline Completion with AI)
    • 用法:Services > Databases > Register DB in Apache NetBeans 中,右鍵點擊資料庫連接並選擇 "Execute Command..."。在開啟的新視窗中撰寫 SQL 查詢,提供AI 驅動的行內補全建議。
    • 說明: 可以在同一個視窗中執行查詢並立即查看結果,簡化工作流程並減少查詢所花費的時間。

how to write Java HTTP client and server for RESTful web services

供程式串接用的網頁服務 (Web Service) 分成客戶端及服務端。以 Java RESTful Web Service 為例,假設服務端點規格如下:

    http://example.com:8080/api/v1/users/123?name=John 

其中,本體區皆以 JSON 物件字串為資料交換標準,輸入參數用到路徑123,查詢字串name=John,標頭區Area: Taipei,本體區phone: 123-4567。其 POST 請求 (Request) 及回應 (Response) 如下,

Request Header and Body
POST /api/users/123?name=John HTTP/1.1
Host: example.com:8080
Accept: application/json
Area: Taipei

{ "phone": "123-4567" }
Response Header and Body
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 85

{
  "id": 123,
  "name": "John",
  "area": "Taipei",
  "phone": "123-4567"
}

以下介紹上述端點規格的服務端及客戶端寫法:

(一) 服務端寫法,將使用 JAX-RS Jersey 套件

A. Java EE 7 手動轉型寫法如下,須搭配 GlassFish 4.1.2 (Java EE 7) with JDK 8

// Old Version:
//  On NetBeans, use Tools/Server 
//    to install GlassFish 4.1.2 (Java EE 7) with JDK 8
//  Use New/RESTful Web Services from Patterns...
//    to set up ApplicationConfig.java and Resource.java
//
import javax.ws.rs.Consumes;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
//import javax.ws.rs.core.Response;
import com.goolge.gson.Gson;  // install gson-2.7.jar in library

@Path("/api/users")
public class UserResource {

    @POST
    @Path("{id}")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public String updateUser(      // 此方法名無關緊要,回傳型別建議用字串
            @PathParam("id") int id,
            @QueryParam("name") String name,
            @HeaderParam("Area") String area,
            String requestBody) {  // 請求本體區建議用字串接收,避免自動轉型出錯

        // 取出請求本體區物件
        PhoneRequest request = new Gson()
            .fromJson(requestBody, PhoneRequest.class); // 字串轉物件

        // 依據給定 id, name, area, request,執行運算邏輯

        // 建構回應物件,轉型成字串回應
        UserResponse response = new UserResponse();
        response.id = id;
        response.name = name;
        response.area = area;
        response.phone = request.phone;

        String jsonResponse = new Gson().toJson(response);  // 物件轉字串
        return jsonResponse;  // 回傳用字串

        //return Response.ok(response).build();  // 回傳用物件,可能報錯
    }

    // Request body class 請求本體物件
    public static class PhoneRequest {

        public String phone;
    }

    // Response body class 回應本體物件
    public static class UserResponse {

        public int id;
        public String name;
        public String area;
        public String phone;
    }
}

B. Jakarta EE 9.1 自動轉型寫法如下,須搭配 GlassFish 6.2.5 (Jakarta EE 9.1) with JDK 11

// New Version:
//  On NetBeans, use Tools/Server 
//    to install GlassFish 6.2.5 (Jakarta EE 9.1) with JDK 11
//  Use New/RESTful Web Services from Patterns...
//    to set up ApplicationConfig.java and Resource.java
//
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;

@Path("/api/users")
public class UserResource {

    @POST
    @Path("{id}")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response updateUser(      // 此方法名無關緊要,回傳型別 Response
            @PathParam("id") int id,
            @QueryParam("name") String name,
            @HeaderParam("Area") String area,
            PhoneRequest requestBody) {  // 請求本體區物件型別 PhoneRequest

        // 依據給定 id, name, area, requestBody,執行運算邏輯

        // 建構回應物件
        UserResponse response = new UserResponse();
        response.id = id;
        response.name = name;
        response.area = area;
        response.phone = requestBody.phone;

        return Response.ok(response).build();  // 回傳成功狀態 Response 物件
        // Response.status(Response.Status.BAD_REQUEST) // 其他錯誤狀態回傳法
        //       .entity("Invalid input")
        //       .build();
    }

    // Request body class 請求本體物件
    public static class PhoneRequest {

        public String phone;
    }

    // Response body class 回應本體物件
    public static class UserResponse {

        public int id;
        public String name;
        public String area;
        public String phone;
    }
}

(二) 至於客戶端有如下三種常用寫法,可供比較選用:

  • JAX-RS 適合用於 Java/Jakarta EE 或 Jersey 等 RESTful 應用。
  • HttpURLConnection 是最基本的方式,無需額外套件,但較繁瑣。
  • HttpClient (JDK 11+) 是現代化且功能強大的選擇,須 JDK11以上才支援。

 A.使用 JAX-RS Client API

// On NetBeans, use New/RESTful Java Client... 
//   to add JAX-RS libraries which support javax/jakarta.ws.rs.* packages
//   and set up NewJerseyClient.java
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

public class JaxRsClientExample {
    public static void main(String[] args) {
        Client client = ClientBuilder.newClient();
        WebTarget target = client
            .target("http://example.com:8080/api/users/123")
            .queryParam("name", "John");

        Invocation.Builder builder = target
            .request(MediaType.APPLICATION_JSON)
            .header("Area", "Taipei");

        String jsonBody = "{ \"phone\": \"123-4567\" }";

        Response response = builder.post(
            Entity.entity(jsonBody, MediaType.APPLICATION_JSON));

        String responseBody = response.readEntity(String.class);
        System.out.println("Response: " + responseBody);
        response.close();
        client.close();
    }
}

B.使用 java.net.HttpURLConnection

import java.io.BufferedReader;
import java.io.IOException;  // thrown by httpURLConnection.openConnection()
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException; // thrown by URL()
import java.net.URL;

public class HttpURLConnectionExample {
    public static void main(String[] args) throws IOException, MalformedURLException {
        URL url = new URL("http://example.com:8080/api/users/123?name=John");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        conn.setRequestMethod("POST");
        conn.setRequestProperty("Accept", "application/json");
        conn.setRequestProperty("Area", "Taipei");
        conn.setRequestProperty("Content-Type", "application/json");
        conn.setDoOutput(true);  // needed before writing the request body

        String jsonInput = "{ \"phone\": \"123-4567\" }";
        // use try with resource block without catch block
        //   output stream will be auto closed when leaving the block
        //   any exception in the block will be passed upward to the calling method
        try (OutputStream os = conn.getOutputStream()) {
            os.write(jsonInput.getBytes());
            os.flush();
        }

        BufferedReader br = new BufferedReader(
            new InputStreamReader(conn.getInputStream()));
        String line;
        StringBuilder response = new StringBuilder();
        while ((line = br.readLine()) != null) {
            response.append(line);
        }

        System.out.println("Response: " + response.toString());
        conn.disconnect();
    }
}

C.使用 java.net.http.HttpClient (JDK 11+)

// JDK 11 above is required
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;

public class HttpClientExample {
    public static void main(String[] args) throws IOException, InterruptedException {
        HttpClient client = HttpClient.newHttpClient();

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("http://example.com:8080/api/users/123?name=John"))
            .header("Accept", "application/json")
            .header("Area", "Taipei")
            .header("Content-Type", "application/json")
            .POST(BodyPublishers.ofString("{ \"phone\": \"123-4567\" }"))
            .build();

        HttpResponse<String> response = client.send(request, BodyHandlers.ofString());

        System.out.println("Response: " + response.body());
    }
}
    參考資料
  1. 對應各 Java/Jakarta EE 版本,與其相容的 GlassFish, JDK 版本可參考下址
    Version history of Java EE, JSF, GlassFish, JDK, and NetBeans

quick ways to initialize a list of numbers or strings in java

Java 快速建立整數與字串清單的寫法 在 Java 中,建立 List<Integer> 與 List<String> 是非常常見的需求。 以下依照不同 JDK 版本,整理出幾種 快速建立可修改(modifiab...

總網頁瀏覽量