当前位置: 首页 > 知识库问答 >
问题:

将带有lambda的类映射到默认值

梁和颂
2023-03-14

后续问题。有这样的等级制度。其中A是基类:

       A 
      / \
     B   C

  |   A    |   |   B       |   |  C      |  
  | getId()|   |A.getId()  |   |A.getId()|
               |isVisible()| 

以及以下内容:

List<A> mappings;

我想将B实例的所有ID映射到B.isVisible()的值,并将C实例的ID映射到TRUE

在最初问题的帮助下,我将其提炼为以下格式:

mappings.stream().filter(a -> a instanceof B)
                 .map(b -> (B)b)
                 .collect(Collectors.toMap(A::getId, m -> m.isVisible()));

丑陋的版本是:

mappings.stream()                       
        .collect(Collectors.toMap(A::getId, m ->
                        {
                            boolean isB = m instanceof B;
                            return isB ? ((B) m).isVisible() : true;
                        }));

有没有帮助改进它,为更优雅的版本提供默认true?

共有3个答案

柳俊彦
2023-03-14

也许您可以使用helper类执行您想要的操作:

class Helper {
    private final Long id;
    private final boolean visible;

    Helper(A a) {
        this.id = a.getID();
        this.visible = a instanceof B ? ((B) a).isVisible() : true;
    }

    Long getId() { return id; }

    boolean isVisible() { return visible; }
}

然后,将列表的每个元素映射到Helper的实例并收集到映射:

Map<Long, Boolean> map = mappings.stream()
    .map(Helper::new)
    .collect(Collectors.toMap(Helper::getId, Helper::isVisible));

解决方案仅将可见的是真还是假委托给助手类,并允许您拥有一个干净的流管道。

作为旁注...一般来说,具有Boolean类型值的映射是毫无意义的,因为您可以使用Set具有相同的语义学:

Set<Long> set = mappings.stream()
    .map(Helper::new)
    .filter(Helper::isVisible)
    .collect(Collectors.toSet());

然后,要知道某个元素是否可见,只需检查它是否属于集合:

boolean isVisible = set.contains(elementId);
凤修为
2023-03-14

如果您无法更改源代码,您可以编写实用程序方法isA来描述您想要的内容,例如:

Map<Integer, Boolean> visibility = mappings.stream().collect(toMap(
        A::getId,
        isA(B.class, B::isVisible, any -> true)
));
static <T, S extends T, R> Function<T, R> isA(Class<? extends S> type,
                                              Function<? super S, R> special,
                                              Function<T, R> general) {

    return it -> type.isInstance(it) ? special.apply(type.cast(it))
                                     : general.apply(it);
}
栾峰
2023-03-14

您的变体

mappings.stream()                       
        .collect(Collectors.toMap(A::getId, m ->
                        {
                            boolean isB = m instanceof B;
                            return isB ? ((B) m).isVisible() : true;
                        }));

这不是很难看吗,因为它表达了你的意图。

但您可以简化它,因为不需要局部变量来保存B的m实例

mappings.stream()                       
        .collect(Collectors.toMap(A::getId, m->m instanceof B? ((B)m).isVisible(): true));

然后,根据经验法则,每当您在复合布尔表达式中有boolean文字时,就有一个没有它的替代方案。

mappings.stream()                       
        .collect(Collectors.toMap(A::getId, m -> !(m instanceof B) || ((B)m).isVisible()));
 类似资料:
  • 我想将字段从映射到类,如果源值为,我想将其转换为基于数据类型的默认值(“”表示字符串,0表示数值类型等)。对于设置值,我不使用常规的setter,而是使用builder(带有protobuf,因此方法的名称为和)。 我的映射器如下所示: 使用此代码生成的映射器实现调用,而不是执行null检查并在source返回时设置默认值。有趣的是,当我向方法添加以下注释时,在实现中出现了空检查。 这是构建器中的

  • 我使用此链接中的以下代码为我的一个数据模型类(JSON到JAXB模型的转换)添加自定义反序列化程序。 我想使用com。fasterxml。杰克逊。jaxrs。json。JacksonJaxbJsonProvider,用于其他数据模型的JSON序列化/反序列化。 JacksonJaxbJsonProvider的默认实现非常适合我的JAXB模型,将超类作为抽象类。但是,一旦我提供了自己的自定义Obje

  • 问题内容: 我所有的数据库表都应有一个endTime字段,默认情况下应为END_OF_TIME或类似的内容。我对2038的限制不满意,所以我希望endTime在mysql中为DATETIME类型。 我的Java代码是: 我可以通过手动创建带有DATETIME类型的endTime字段的表来解决,而不是将实体endTime映射到该列,但是我希望Hibernate自动生成表- 我该怎么做? 问题答案:

  • 我在一个项目中使用Spring Boot和Data REST,我想禁用以下默认映射来调试映射问题: 我发现这个问题禁用了,这会导致这些映射不被映射。但是,我的控制器映射也不会被映射。 我可以在保留我定义的映射时禁用这些映射吗? 提前谢谢。

  • 问题内容: 我正在使用glassfish和jaas模块。 我以这种方式配置了web.xml。 这意味着所有要访问我的Web应用程序的用户都必须是组用户。 然后在glassfish控制台上,我需要在以下选项中打勾:配置->服务器配置->安全性->默认主体到角色映射 我的问题是,为什么我需要将此默认主体打勾到角色映射?以及如何更改我的web.xml以避免打勾呢? 非常感谢 洛伊奇 问题答案: 当您指定

  • avro.version= 在avro模式中,map type不支持缺省值。我尝试了以下不同的模式。 第一: 第二: 第三: Java代码如下: 我只希望constraintQuantities和RawQuanties为null。因为这些是可选字段。即使我没有将它们设置为null,它也会抛出异常。 最重要的是,方法生成java POJO,但无法构建该对象。 如果不设置它们为空,然后接收以下异常: