2010-10-14 33 views
13

Tôi có một vài chức năng trong mã của tôi, nơi nó có ý nghĩa nhiều (dường như thậm chí bắt buộc) để sử dụng ghi nhớ.Java: tự động ghi nhớ

Tôi không muốn triển khai thủ công từng chức năng một cách thủ công. Có cách nào đó không (ví dụ: like in Python) Tôi chỉ có thể sử dụng chú thích hoặc làm điều gì khác để tôi tự động nhận được các chức năng này ở nơi tôi muốn?

Trả lời

10

Mùa xuân 3.1 hiện cung cấp @Cacheable annotation, thực hiện chính xác điều này.

Như tên ngụ ý, @Cacheable được sử dụng để phân định phương pháp có thể lưu vào bộ nhớ cache - nghĩa là các phương pháp được lưu trữ vào bộ nhớ cache để các lời gọi tiếp theo (với cùng đối số), giá trị trong cache được trả về mà không phải thực thi phương thức.

4

Tôi không nghĩ rằng có một ngôn ngữ bản địa thực hiện ghi nhớ.

Nhưng bạn có thể triển khai dễ dàng, như một người trang trí cho phương pháp của bạn. Bạn phải duy trì Bản đồ: chìa khóa của Bản đồ của bạn là thông số, giá trị là kết quả.

Đây là một thực hiện đơn giản, đối với một phương pháp one-arg:

Map<Integer, Integer> memoizator = new HashMap<Integer, Integer>(); 

public Integer memoizedMethod(Integer param) { 

    if (!memoizator.containsKey(param)) { 
     memoizator.put(param, method(param)); 
    } 

    return memoizator.get(param); 
} 
+0

Làm cách nào để triển khai theo cách tổng quát với tư cách là người trang trí cho phương pháp của tôi? – Albert

+0

@Albert: Như Benoit đã nói, không có việc triển khai bản địa này (nghĩa là bạn không thể làm điều này theo cách chung mà không cần hack Java), vì công cụ trang trí python sử dụng một số "siêu thông tin" về hàm. I E. có thể trong python để cho người trang trí thay đổi chức năng ban đầu. Đây là - theo như tôi biết - không thể trong Java. – phimuemue

+0

"bạn có thể thực hiện nó một cách dễ dàng, như một trang trí của phương pháp của bạn." <- làm thế nào tôi có thể làm điều đó như một người trang trí? Hay ý bạn là gì? – Albert

6

Tôi đã xem qua một thư viện memoization gọi Tek271 mà dường như sử dụng chú thích để memoize chức năng như bạn mô tả.

+0

Ah tôi hiểu rồi. Dường như lib cung cấp một cách để tạo một đối tượng bao bọc cho đối tượng của bạn và nó tự động ghi nhớ các chức năng đã được đánh dấu để ghi nhớ thông qua một chú thích. – Albert

+1

Trang đã chuyển và hiện có thể tìm thấy tại http://www.tek271.com/software/java/memoizer –

3

Bạn có thể sử dụng giao diện Function trong thư viện guava của Google để dễ dàng đạt được những gì bạn đang sau:

import java.util.HashMap; 
import java.util.Map; 

import com.google.common.base.Function; 

public class MemoizerTest { 
    /** 
    * Memoizer takes a function as input, and returns a memoized version of the same function. 
    * 
    * @param <F> 
    *   the input type of the function 
    * @param <T> 
    *   the output type of the function 
    * @param inputFunction 
    *   the input function to be memoized 
    * @return the new memoized function 
    */ 
    public static <F, T> Function<F, T> memoize(final Function<F, T> inputFunction) { 
    return new Function<F, T>() { 
     // Holds previous results 
     Map<F, T> memoization = new HashMap<F, T>(); 

     @Override 
     public T apply(final F input) { 
     // Check for previous results 
     if (!memoization.containsKey(input)) { 
      // None exists, so compute and store a new one 
      memoization.put(input, inputFunction.apply(input)); 
     } 

     // At this point a result is guaranteed in the memoization 
     return memoization.get(input); 
     } 
    }; 
    } 

    public static void main(final String[] args) { 
    // Define a function (i.e. inplement apply) 
    final Function<Integer, Integer> add2 = new Function<Integer, Integer>() { 
     @Override 
     public Integer apply(final Integer input) { 
     System.out.println("Adding 2 to: " + input); 
     return input + 2; 
     } 
    }; 

    // Memoize the function 
    final Function<Integer, Integer> memoizedAdd2 = MemoizerTest.memoize(add2); 

    // Exercise the memoized function 
    System.out.println(memoizedAdd2.apply(1)); 
    System.out.println(memoizedAdd2.apply(2)); 
    System.out.println(memoizedAdd2.apply(3)); 
    System.out.println(memoizedAdd2.apply(2)); 
    System.out.println(memoizedAdd2.apply(4)); 
    System.out.println(memoizedAdd2.apply(1)); 
    } 
} 

nên in:

Thêm 2 đến: 1

Thêm 2 vào: 2

Thêm 2 đến: 3

Thêm 2 đến: 4

Bạn có thể thấy rằng 2 time memoizedAdd2 được gọi (áp dụng) cho các đối số 2 và 1, tính toán trong áp dụng không thực sự chạy, nó chỉ lấy các kết quả được lưu trữ.

+0

Đến gần hơn với những gì tôi muốn nhưng vẫn quá cụ thể. Có thể khái quát hóa điều này nhiều hơn để nó có thể lấy bất kỳ số tham số nào (và không chỉ một tham số)? – Albert

+0

Lớp chức năng của ổi ngưng tụ tất cả đầu vào thành một đối số duy nhất. Bây giờ, kiểu của đối số đó có thể là một đối tượng [], có hiệu quả cho phép bất cứ điều gì, nhưng làm giảm hiệu quả của việc đánh máy. Hoặc, nó sẽ là khá đơn giản để tạo ra một giao diện Function2 mới được tạo ra bởi cho 2 đối số, một Function3 ,… –

+0

Trong lớp Nhà cung cấp có các phương thức memoize và memoizeWithExpiration được xây dựng sẵn. – lbalazscs

0

Cyclops cung cấp Memoisation cho Chức năng, nhà cung cấp, Callables, vị từ và bằng các phương pháp mở rộng (thông qua phương pháp Tài liệu tham khảo) (see javadoc)

Ví dụ:

Với một biến gọi là đếm số lần mà phương thức của chúng ta thực sự được gọi, chúng ta có thể thấy hàm được ghi nhớ thực sự thực hiện phương thức một lần.

int called = 0; 

cached = Memoise.memoiseQuadFunction(this::addAll); 

assertThat(cached.apply(1,2,3,4),equalTo(10)); 
assertThat(cached.apply(1,2,3,4),equalTo(10)); 
assertThat(called,equalTo(1)); 

private int addAll(int a,int b,int c, int d){ 
    called++; 
    return a+b+c+d; 
} 
Các vấn đề liên quan