持有一个具有不同参数数量的函数映射。

huangapple 未分类评论50阅读模式
英文:

Holding a Map of functions with differing number of args

问题

我试图编写一个实用类,它可以接受一个 StringClass<?>,然后返回一个真正是该 String 类型实例的 Object

例如,如果我有字符串 "FALSE" 和类 "java.lang.Boolean",我想返回类型化的 Boolean.FALSE。对于其他类似String、Long、Int、Enum等的情况也一样。

我希望这样做的方式不需要在添加新类型时进行太多重写。目前我有一个签名为 Object getTypedValue(Class<?> clazz, String value); 的方法。

从这里,我认为我可以使用一个 Map<Class<?>, Function<String, Object>>。这对于String和Boolean等情况都可以正常工作,但是对于Enum情况,我需要类名。因此,Map 变成了 Map<Class<?>, BiFunction<String, Class<?>, Object>>

但是大多数方法不需要 Class 参数。我还发现,像这样的新的 FunctionalInterface:

@FunctionalInterface
public interface OptionalClassFunction<T, CLAZZ, R> {
  
  R apply(T t, CLAZZ... clazz);

}

当我只传递 T 作为 lambda 时似乎不起作用。

例如:

ImmutableMap.of(
  Boolean.class, Util::toBoolean
)

private Boolean toBoolean(String value);

不起作用。

对于如何做类似以下的事情有任何建议吗:

Map<Class<?>, WhateverFunction<String, MAYBE_A_CLASS, Object>>?

示例方法可能如下:

  public static Boolean toBoolean(String value) {
    // 推导布尔值
  }

  public static Enum toEnum(String value, Class<?> fieldType) {
    // 推导枚举值
  }
英文:

I am trying to write a utility class that can take in a String and Class<?> and return back an Object that is really the typed instance of that String.

For example, if I have string "FALSE" and class "java.lang.Boolean", I want to return the typed Boolean.FALSE. Etc for other classes like String, Long, Int, Enum, etc.

I want to do this in a way that doesn't need too much re-writing when a new type is added. Currently I have a method with signature Object getTypedValue(Class<?> clazz, String value);.

From here, I thought I could use a Map<Class<?>, Function<String, Object>>. This works fine for cases like String and Boolean, but with the Enum case, I need the class name as well. So then the Map becomes Map<Class<?>, BiFunction<String, Class<?>, Object>>.

But most of the methods do not need the Class parameter. Have also found that a new FunctionalInterface like:

@FunctionalInterface
public interface OptionalClassFunction<T, CLAZZ, R> {
  
  R apply(T t, CLAZZ... clazz);

}

does not seem to work when I pass a method with only the T as the lambda.

e.g.

ImmutableMap.of(
  Boolean.class, Util::toBoolean
)

private Boolean toBoolean(String value);

does not work.

Any suggestions on how to so something like:

Map<Class<?>, WhateverFunction<String, MAYBE_A_CLASS, Object>> ?

Example methods would be:

  public static Boolean toBoolean(String value) {
    // derive bool
  }

  public static Enum toEnum(String value, Class<?> fieldType) {
    // derive enum
  }

答案1

得分: 0

为什么需要枚举的类名?

例如,DayOfWeek 是一个枚举类,就像每个其他的枚举类一样,它有一个 valueOf(String name) 方法,因此只需注册如下内容:

DayOfWeek.class, DayOfWeek::valueOf

如果您不喜欢 valueOf 方法,例如因为它区分大小写,而您的 toEnum 方法更好,那么可以编写一个辅助方法来封装它,例如:

public static <T extends Enum<T>> Function<String, T> getEnumParser(Class<T> type) {
    return s -> toEnum(s, type);
}

public static <T extends Enum<T>> T toEnum(String value, Class<T> type) {
    for (T constant : type.getEnumConstants())
        if (constant.name().equalsIgnoreCase(value))
            return constant;
    throw new IllegalArgumentException("Unknown constant for enum " + type.getName() + ": \"" + value + "\"");
}

然后您可以这样注册它:

DayOfWeek.class, Util.getEnumParser(DayOfWeek.class)

这个辅助方法很好,但实际上您并不是真的需要它:

DayOfWeek.class, s -> Util.toEnum(s, DayOfWeek.class)

除非在与 ImmutableMap.of(...) 一起使用时可能会让编译器感到困惑。辅助方法可以修复潜在的编译器推断问题。

英文:

Why would you need the class name for enums?

E.g. DayOfWeek is an enum, and like every other enum class, it has a valueOf(String name) method, so simply register this:

DayOfWeek.class, DayOfWeek::valueOf

If you don't like the valueOf method, e.g. because it is case-sensitive, and your toEnum method is better, then write a helper method to encapsulate that, e.g.

public static &lt;T extends Enum&lt;T&gt;&gt; Function&lt;String, T&gt; getEnumParser(Class&lt;T&gt; type) {
	return s -&gt; toEnum(s, type);
}

public static &lt;T extends Enum&lt;T&gt;&gt; T toEnum(String value, Class&lt;T&gt; type) {
	for (T constant : type.getEnumConstants())
		if (constant.name().equalsIgnoreCase(value))
			return constant;
	throw new IllegalArgumentException(&quot;Unknown constant for enum &quot; + type.getName() + &quot;: \&quot;&quot; + value + &quot;\&quot;&quot;);
}

You then register it using:

DayOfWeek.class, Util.getEnumParser(DayOfWeek.class)

The helper is nice, but you don't really need it:

DayOfWeek.class, s -&gt; Util.toEnum(s, DayOfWeek.class)

except that might confuse the compiler when used with ImmutableMap.of(...). The helper fixes that potential compiler inference problem.

答案2

得分: 0

> 有没有关于如何执行类似以下操作的建议:

>
> Map<Class<?>, WhateverFunction<String, MAYBE_A_CLASS, Object>>

始终将其作为BiFunction,并简单地忽略Class&lt;?&gt;参数:

Map&lt;Class&lt;?&gt;, BiFunction&lt;String, Class&lt;?&gt;, Object&gt;&gt; map = Map.of(
        Boolean.class, (s,t) -&gt; Util.toBoolean(s),
        Enum.class, Util::toEnum
);

由于使用映射的用户不知道是否需要Class&lt;?&gt;参数,它必须始终传递该值,例如:

Class&lt;?&gt; type = ...
String value = ...

Object obj = map.get(type).apply(value, type);

简化。通常在get()调用之后检查null。

当然,那也行不通,因为调用者认为类型是例如DayOfWeek,所以如果调用者执行type = DayOfWeek.class,查找将失败。现在,调用者所需的逻辑突然变得复杂。

解决方法是将get-apply逻辑封装在一个辅助方法中,这样您可以将映射查找的DayOfWeek.class替换为Enum.class,但如果这样做,您可能会直接构建对枚举的支持,绕过映射,并将映射保留为Function

英文:

> Any suggestions on how to so something like:
>
> Map<Class<?>, WhateverFunction<String, MAYBE_A_CLASS, Object>>

Always make it a BiFunction, and simply ignore the Class&lt;?&gt; parameter:

Map&lt;Class&lt;?&gt;, BiFunction&lt;String, Class&lt;?&gt;, Object&gt;&gt; map = Map.of(
        Boolean.class, (s,t) -&gt; Util.toBoolean(s),
        Enum.class, Util::toEnum
);

Since the user of the map wouldn't know if the Class&lt;?&gt; parameter is needed, it would have to always pass the value, e.g.

Class&lt;?&gt; type = ...
String value = ...

Object obj = map.get(type).apply(value, type);

Simplified. You'd normally check for null after the get() call.

Of course, that won't work either, because the caller thinks the type is e.g. DayOfWeek, so if caller does type = DayOfWeek.class, the lookup would fail. Now suddenly the logic needed by the caller is getting complex.

Solution for that is to encapsulate the get-apply logic in a helper method, so you can substitute DayOfWeek.class with Enum.class for the map lookup, but if you do that, you might as well just build in straight support for enums, bypassing the map, and leave the map with Function.

huangapple
  • 本文由 发表于 2020年4月7日 07:31:12
  • 转载请务必保留本文链接:https://java.coder-hub.com/61070526.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定