泛型java中的动态数据类型

Posted

技术标签:

【中文标题】泛型java中的动态数据类型【英文标题】:Dynamic datatype in generics java 【发布时间】:2021-07-28 14:09:47 【问题描述】:

我有一个用例,客户端发送列表。任务是迭代并执行该函数并将其保存在 TypedSafeMap 中。 伪客户端代码:

Function<String, Integer> firstFn = x -> x.length();
Function<String, String> secondFn = x -> x.substring(0);

client.runTheseFunctions(Arrays.asList(firstFn, secondFn));

在代码中的runtTheseFunctions内部,任务是执行这些函数并将其保存在一个TypedSafeMap中,其中key是函数结果类型的数据类型,value是functions.apply()的返回值;

下面的代码

public static void runTheseFunctions(List<Function<Employee, ?>> lst, Employee o) 
           lst.stream().forEach( x -> 
             typedSafeMap.put(????, x.apply(o));  
        //The key is nothing but the datatype of the x.apply(o).
        //How do I add this in runtime here. Generics is all compile time safety.
           );
    

【问题讨论】:

【参考方案1】:

增强@Yonas 答案:

private static Map<?, ? extends Object> runTheseFunctions(List<Function<String, ? extends Object>> list, String o) 
    return list.stream()
            .map(f -> f.apply(o))
            .collect(Collectors.toMap(result -> result.getClass(), Function.identity()));

这将只调用一次f.apply(o)

【讨论】:

【参考方案2】:

如果函数列表包含两个或多个具有相同输出类型的函数(例如:String getFirstName、String getLastName、toMap 将失败。所以另一种选择是:

var map = list.stream().collect(groupingBy(
    f -> f.apply(e).getClass(), 
    mapping(f -> f.apply(e), toList())
));

【讨论】:

【参考方案3】:

这是您想要实现的目标的示例,您可以将其用于测试。我假设 Employee 类的一个简单实现,只是为了给你一个想法:

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

class Employee 
    String name;

    public Employee(String name) 
        this.name = name;
    

    public int length() 
        return name.length();
    

    public String substring(int index) 
        return name.substring(index);
    


public class Test 

    public static void main(String[] args) 

        Employee e = new Employee("Marco");

        Function<Employee, Integer> firstFn = x -> x.length();
        Function<Employee, String> secondFn = x -> x.substring(0);

        runTheseFunctions(Arrays.asList(firstFn, secondFn), e);

    

    public static void runTheseFunctions(List<Function<Employee, ?>> lst, Employee o) 

        Map<Class, Object> typedSafeMap = new HashMap<>();

        lst.stream().forEach(x -> 

            Object result = x.apply(o);

            typedSafeMap.put(x.apply(o).getClass(), x.apply(o));
            // The key is nothing but the datatype of the x.apply(o).
            // How do I add this in runtime here. Generics is all compile time safety.
        );

        typedSafeMap.entrySet().forEach(entry -> System.out.println(entry.getKey() + " - " + entry.getValue()));
    


这是输出:

class java.lang.String - Marco
class java.lang.Integer - 5

【讨论】:

【参考方案4】:

您可以实现您的“runTheseFunctions”方法,如下所示:

    public static void runTheseFunctions(List<Function<Employee, ?>> lst, Employee o) 
        Map<Class<?>, Object> typedSafeMap = new HashMap<>();

        lst.stream().forEach(x -> 
            Object value = x.apply(o);
            typedSafeMap.put(value.getClass(), value);
        );

        System.out.println(typedSafeMap);
    

【讨论】:

不错。我们有同样的想法伙伴;) 您可以将x.apply(o) 方法移动到map 而不是forEach 然后collect 结果。 .map(f -&gt; f.apply(o)).collect(Collectors.toMap(result -&gt; result.getClass(), Function.identity()));【参考方案5】:
public static void runTheseFunctions(List<Function<Employee, ?>> lst, Employee o) 
    lst.stream().collect(Collectors.toMap(f -> f.apply(o).getClass(), f -> f.apply(o)));

【讨论】:

这是一个不错的解决方案。 您可以将f.apply(o) 移动到stream.map(f -&gt; f.apply(o)),这样就不需要在collect 中调用两次。

以上是关于泛型java中的动态数据类型的主要内容,如果未能解决你的问题,请参考以下文章

JAVA中,关于可变参数和泛型的问题。

java泛型中的通配符

JavaSE-泛型

Java集合:整体结构

Java泛型学习笔记 - 泛型方法

深入理解 Dart 中的类型系统和泛型