簡體   English   中英

我如何將 map 的字符串轉換為 Java 中的 function?

[英]How can I map a String to a function in Java?

目前,我有一堆 Java 實現Processor接口的類,這意味着它們都有一個processRequest(String key)方法。 這個想法是每個 class 都有幾個(比如,<10)成員Strings ,並且每個都通過processRequest方法映射到 class 中的一個方法,如下所示:

class FooProcessor implements Processor
{
    String key1 = "abc";
    String key2 = "def";
    String key3 = "ghi";
    // and so on...

    String processRequest(String key)
    {
        String toReturn = null;
        if (key1.equals(key)) toReturn = method1();
        else if (key2.equals(key)) toReturn = method2();
        else if (key3.equals(key)) toReturn = method3();
        // and so on...

        return toReturn;
    }

    String method1() { // do stuff }
    String method2() { // do other stuff }
    String method3() { // do other other stuff }
    // and so on...
}

你明白了。

這對我來說工作正常,但現在我需要一個從鍵到 function 的運行時可訪問映射; 並非每個 function實際上都返回一個字符串(有些返回無效),我需要動態訪問每個 class 中每個 function 的返回類型(使用反射),其中有一個鍵。 我已經有一個經理知道所有的鍵,但知道從鍵到 function 的映射。

我的第一直覺是使用if-else語句將此映射替換為Map<String, Function> ,就像我在 Javascript 中所做的那樣。但是,Java 不支持一流的函數,所以我在那里運氣不好。 我可能會挖掘一個第三方庫,讓我使用一流的功能,但我還沒有看到,我懷疑我需要一個全新的庫。

我還考慮過將這些String鍵放入數組中並使用反射按名稱調用方法,但我看到此方法有兩個缺點:

  • 我的密鑰必須與方法命名相同 - 或者以特定的、一致的方式命名,以便很容易將它們 map 到方法名稱。
  • 這似乎比我現在擁有的if-else語句慢得多。 效率是一個值得關注的問題,因為這些方法往往會被非常頻繁地調用,我想盡量減少不必要的開銷。

TL; DR:我正在尋找一種干凈、開銷最小的方法,將 map String轉換為某種Function object,我可以調用和調用(類似) getReturnType() 如果它真的符合我的需要,我並不特別介意使用第三方庫。 我也不介意使用反射,盡管我強烈希望每次執行方法查找時都避免使用反射——也許使用一些將Map與反射相結合的緩存策略。

關於獲得我想要的東西的好方法的想法? 干杯!

沒有任何一流的獨立函數,但您可以使用接口做您想做的事。 創建一個代表您的功能的接口。 例如,您可能有以下情況:

public interface ComputeString
{
    public String invoke();
}

然后,您可以首先創建您想要的Map<String,ComputeString>對象。 使用地圖會比反射快得多,並且也會提供更多的類型安全性,所以我會建議上述內容。

雖然您不能擁有一流的功能,但有一些匿名類可以基於接口:

interface ProcessingMethod {
   String method();
}

Map<String, ProcessingMethod> methodMap = new HashMap<String, ProcessingMethod>();
methodMap.put("abc", new ProcessingMethod() {
   String method() { return "xyz" }
});
methodMap.put("def", new ProcessingMethod() {
   String method() { return "uvw" }
});

methodMap.get("abc").method();

或者你可以使用 Scala :-)

示例使用命名函數的enum和抽象FunctionAdapter來調用具有可變數量的同構參數的函數而無需反射。 lookup()函數只使用Enum.valueOf ,但對於大量函數Enum.valueOf ,一個Map可能是值得的。

你不能做String to Method嗎? 然后你可以緩存你需要執行的方法。

正如您所注意到的,您可以使用Reflection API做您想做的事情,但是除了您已經提出的問題之外,您還失去了 Java 編譯器的一些好處。 將您的字符串包裝在一個對象中並使用訪問者模式會解決您的問題嗎? 每個StringWrapper只接受具有正確方法的Visitor ,或者類似的東西。

使用 Map,其中鍵是字符串,值是實現包含 method() 的接口的對象。 這樣您就可以從地圖中獲取包含您想要的方法的對象。 然后只需在對象上調用該方法。 例如:

class FooProcessor implements Processor{

    Map<String, FooMethod> myMap;

    String processRequest(String key){
        FooMethod aMethod = myMap.getValue(key);
        return aMethod.method();
    }        
}

反射 API 中的Method類怎么樣? 您可以根據名稱、參數或返回類型查找類的方法。 然后你只需調用 Method.invoke(this, parameters)。

這與您正在談論的 JavaScript 中的 Map 幾乎相同。

public class CarDetailsService {

    private final CarRepository carRepository;

    private final Map<String, Function<CarDTO, String>> carColumnMapper = new HashMap<>();

    public ApplicationDetailsServiceImpl(CarRepository carRepository) {
        this.carRepository = carRepository;

       //---- Initialise all the mappings ------- //

        carColumnMapper.put("BRAND", CarDTO::getBrandName);
        carColumnMapper.put("MILEAGE", CarDTO::getMileage);
    }

    public Map<String, List<CarDTO>> getListOfCars(String groupBy) {

        return carRepository.findAll()
                .stream()
                .map(toCarDTO)
                .collect(groupingBy(carColumnMapper.get(groupBy.toUpperCase())));
    }

    Function<CarDetails, CarDTO> toCarDTO = (carDetails) -> CarDTO
            .builder()
            .brand(carDetails.getBrand())
            .engineCapacity(carDetails.getEngineCapacity())
            .mileage(carDetails.getMileage())
            .fuel(carDetails.getFuel())
            .price(carDetails.getPrice())
            .build();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM