1

I have this function and it returns an object because it has no ideas what the return could be. It could be in long, int, String, or Foo

@SuppressWarnings("unchecked")
public Optional<Object> getRequestByFieldName(String fieldName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    Class<?> classA = instanceA.getClass();

    Method method = classA.getMethod("getAllFields");

    Object o =  method.invoke(instanceA);

    // I'm using protobuf to get the field value,
    // but a field could be missing because someone didn't send it
    // in that case I return an Optional Empty object
    Map<Descriptors.FieldDescriptor, Object> objectMap = (Map) o;

    Object fieldValue =  objectMap.entrySet().stream()
            .filter(fieldDescriptorObjectEntry -> {
                Descriptors.FieldDescriptor descriptor = fieldDescriptorObjectEntry.getKey();
                return descriptor.getName().equals(fieldName);
            })
            .findFirst().map(fieldDescriptorObjectEntry -> fieldDescriptorObjectEntry.getValue())
            .orElse(Optional.empty());

    return Optional.of(fieldValue);
}

How do I use this function to assign a variable to an int, long or Foo? This is what I currently have:

long someUid = (long) getRequestByFieldName("some_uid").orElse(0);

However, I keep getting this error if the field was missing:

java.util.Optional cannot be cast to java.lang.Long

If the field is not present you end up assigning Optional.empty() to the fieldValue variable.

Object fieldValue =  objectMap.entrySet().stream()
        .filter(fieldDescriptorObjectEntry -> {
            Descriptors.FieldDescriptor descriptor = fieldDescriptorObjectEntry.getKey();
            return descriptor.getName().equals(fieldName);
        })
        .findFirst().map(fieldDescriptorObjectEntry -> fieldDescriptorObjectEntry.getValue())
        .orElse(Optional.empty()); // ISSUE HERE

You then return with return Optional.of(fieldValue). This means, when no field is found, you return an Optional<Optional<?>> so when doing the following:

long someUid = (long) getRequestByFieldName("some_uid").orElse(0);

The orElse bit is never called because the Optional is never empty. Instead, it holds an Optional which obviously can't be cast to Long. From your code, you should be able to simply return the result of map, like so:

return objectMap.entrySet().stream()
        .filter(fieldDescriptorObjectEntry -> {
            Descriptors.FieldDescriptor descriptor = fieldDescriptorObjectEntry.getKey();
            return descriptor.getName().equals(fieldName);
        })
        .findFirst()
        .map(fieldDescriptorObjectEntry -> fieldDescriptorObjectEntry.getValue());

Whether or not this completely solves the casting problem depends on how you determine what type of object the Optional holds.

4

1 回答 1

4

如果该字段不存在,您最终会分配Optional.empty()给该fieldValue变量。

Object fieldValue =  objectMap.entrySet().stream()
        .filter(fieldDescriptorObjectEntry -> {
            Descriptors.FieldDescriptor descriptor = fieldDescriptorObjectEntry.getKey();
            return descriptor.getName().equals(fieldName);
        })
        .findFirst().map(fieldDescriptorObjectEntry -> fieldDescriptorObjectEntry.getValue())
        .orElse(Optional.empty()); // ISSUE HERE

然后你返回return Optional.of(fieldValue). 这意味着,当没有找到字段时,您Optional<Optional<?>>在执行以下操作时返回一个 so:

long someUid = (long) getRequestByFieldName("some_uid").orElse(0);

orElse永远不会被调用,因为Optional永远不会为空。相反,它拥有一个Optional显然不能转换为Long. 从您的代码中,您应该能够简单地返回 的结果map,如下所示:

return objectMap.entrySet().stream()
        .filter(fieldDescriptorObjectEntry -> {
            Descriptors.FieldDescriptor descriptor = fieldDescriptorObjectEntry.getKey();
            return descriptor.getName().equals(fieldName);
        })
        .findFirst()
        .map(fieldDescriptorObjectEntry -> fieldDescriptorObjectEntry.getValue());

这是否完全解决了铸造问题取决于您如何确定Optional所持有的对象类型。

于 2018-12-27T23:14:34.157 回答