首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 惰性計算入門:從 Iterator 模擬到 Totally Lazy 框架的無限序列實戰

     編輯:Java 相關知識

什麼是惰性計算?

惰性計算指「盡可能延遲表達式求值」。對比嚴格求值(如 Java 默認):

print length([2+1, 3*2, 1/0, 5-4])
// 嚴格語言:編譯/運行拋出 DivByZero 異常(第三個元素 1/0)
// 惰性語言:輸出 4(僅計算列表長度,不求值元素)

優勢:

  1. 推遲耗時計算至真正需要時。
  2. 支持無限集合(按需產生元素)。
  3. map/filter 等鏈式操作避免中間集合創建,效率更高。

Java 無原生惰性支持,但可通過 Iterator、第三方庫(Commons Collections、Totally Lazy)實現。

一、手寫惰性迭代器:無限素數序列

基於經典素數判斷算法(見下),實現 Iterator<Integer> 按需產生下一個素數。

public class Prime {
    public static boolean isFactor(int p, int n) { return n % p == 0; }
    public static Set<Integer> getFactors(int n) { ... }
    public static int sumFactors(int n) { ... }
    public static boolean isPrime(int n) { return n==2 || sumFactors(n)==n+1; }
    public static int nextPrimeFrom(int last) { do last++; while(!isPrime(last)); return last; }
}

惰性迭代器實現

public class PrimeIterator implements Iterator<Integer> {
    private int lastPrime = 1;
    public boolean hasNext() { return true; } // 素數無限
    public Integer next() {
        return lastPrime = Prime.nextPrimeFrom(lastPrime); // 更新並返回
    }
    public void remove() { throw new UnsupportedOperationException(); }
}

測試驗證

@Test public void prime_iterator() {
    Iterator<Integer> it = new PrimeIterator();
    for (int expected : PRIMES_BELOW_50) assertEquals(expected, it.next());
}

雖非標準迭代器用法,但完美模擬惰性集合「按需生成、無限長度」特性。

二、Jakarta Commons LazyList:裝飾器 + 工廠模式

LazyList.decorate(list, factory) 包裝現有列表,索引訪問時若無值則調用工廠生成。

List<Integer> primes = new ArrayList<>();
List<Integer> lazyPrimes = LazyList.decorate(primes, new PrimeFactory());
for (int i=0; i
public class PrimeFactory implements Factory {
    private int index = 0;
    public Object create() { return Prime.indexedPrime(index++); }
}

缺陷:工廠無感知請求索引,需自維護狀態(如 index),且列表必須預初始化為空以保持索引同步,耦合度高。

三、Totally Lazy:一流惰性框架與流式 API

Totally Lazy 將惰性貫穿框架設計,大量使用靜態導入構建可讀性極強的 DSL 風格代碼。

素數判斷的函數式重寫

import static com.googlecode.totallylazy.Predicates.is;
import static com.googlecode.totallylazy.numbers.Numbers.*;

public class Prime {
    public static Predicate<Number> isFactor(Number n) {
        return where(remainder(n), is(zero)); // n % factor == 0
    }
    public static Sequence<Number> factors(Number n) {
        return range(1, n).filter(isFactor(n)); // 1..n 過濾因子
    }
    public static Number sumFactors(Number n) {
        return factors(n).reduce(sum); // 求和
    }
    public static boolean isPrime(Number n) {
        return equalTo(increment(n), sumFactors(n)); // n+1 == sum(factors)
    }
}

代碼如規格文檔般清晰,where、remainder、range、filter、reduce 均為惰性操作。

優化版:平方根對稱因子 + 記憶化

public class PrimeFast {
    public static Sequence<Number> getFactors(final Number n) {
        Sequence<Number> lower = range(1, squareRoot(n)).filter(isFactor(n));
        return lower.join(lower.map(divide(n))); // 對稱生成大因子
    }
    public static Sequence<Number> factors(final Number n) {
        return getFactors(n).memorise(); // 記憶化緩存
    }
    // sumFactors、isPrime 同前
}

memorise() 自動緩存相同參數調用結果,無需手工 Map 存儲。

框架內建無限素數序列

public static Function1<Number, Number> nextPrime = n -> nextPrime(n);
public static Computation<Number> primes = computation(2, computation(3, nextPrime));
public static Sequence<Number> primes() { return primes; }

public static Number nextPrime(Number n) {
    return iterate(add(2), n).filter(prime).second(); // 從 n+2 起步,過濾素數,取第二個
}

典型惰性模式:種子值 + 生成下一元素的函數 組合成 Computation,轉為 Sequence 即得無限惰性序列。

總結與展望

  • Iterator:零依賴、輕量,適合簡單無限序列。
  • Commons LazyList:入門級惰性列表,但工廠設計有缺陷。
  • Totally Lazy:功能最全、API 最優雅,內建記憶化、無限序列、豐富組合子,適合生產級函數式編程。

下一期將探討 Groovy、Scala、Clojure 中的原生惰性支持與對比。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved