Java 将具有lambda的类映射到默认值
我的后续问题。 有这样的等级制度。其中A是基类:Java 将具有lambda的类映射到默认值,java,lambda,java-8,Java,Lambda,Java 8,我的后续问题。 有这样的等级制度。其中A是基类: A / \ B C | A | | B | | C | | getId()| |A.getId() | |A.getId()| |isVisible()| 以及以下内容: List<A> mappings; 丑陋的版本是: mappings.stream()
A
/ \
B C
| A | | B | | C |
| getId()| |A.getId() | |A.getId()|
|isVisible()|
以及以下内容:
List<A> mappings;
丑陋的版本是:
mappings.stream()
.collect(Collectors.toMap(A::getId, m ->
{
boolean isB = m instanceof B;
return isB ? ((B) m).isVisible() : true;
}));
有没有关于改进它以提供更优雅版本的默认值的帮助?您的代码很难看,因为您的层次结构没有意义。您可能想要的是:
class A
{
abstract public boolean isVisible();
// or make it concrete and return a default if you need to
}
// B can stay the same (+ @Override)
class C extends A
{
@Override
public boolean isVisible()
{
return true;
}
}
然后我们可以做:
mappings.stream()
.collect(Collectors.toMap(A::getId, m -> m.isVisible()));
我编写了这个简单的
收集器
实现,它可以实现您想要的功能:
public class AToMapCollector implements Collector<A, Map<Integer, Boolean>, Map<Integer, Boolean>>{
@Override
public Supplier<Map<Integer, Boolean>> supplier(){
return HashMap::new;
}
@Override
public BiConsumer<Map<Integer, Boolean>, A> accumulator(){
return (map, a) -> {
boolean visible = true;
if(a instanceof B){
visible = ((B) a).isVisible();
}
map.put(a.getId(), visible);
};
}
@Override
public BinaryOperator<Map<Integer, Boolean>> combiner(){
return (map1, map2) -> {
map1.putAll(map2);
return map1;
};
}
@Override
public Function<Map<Integer, Boolean>, Map<Integer, Boolean>> finisher(){
return map -> map;
}
@Override
public Set<Characteristics> characteristics(){
return EnumSet.of(Characteristics.IDENTITY_FINISH, Characteristics.UNORDERED);
}
}
公共类AToMapCollector实现收集器{
@凌驾
公共供应商(){
返回HashMap::new;
}
@凌驾
公共双消费者累加器(){
返回(地图,a)->{
布尔可见=真;
if(B的a实例){
可见=((B)a).isVisible();
}
put(a.getId(),可见);
};
}
@凌驾
公共二进制运算符组合器(){
返回(map1、map2)->{
map1.putAll(map2);
返回map1;
};
}
@凌驾
公共函数完成器(){
返回地图->地图;
}
@凌驾
公共集特征(){
返回枚举集(Characteristics.IDENTITY\u FINISH,Characteristics.UNORDERED);
}
}
最后可以这样称呼:
Map<Integer, Boolean> map = mappings.stream().collect(new AToMapCollector());
Map Map=mappings.stream().collect(新的AToMapCollector());
添加创建一个全新的类是该收集器的可重用性,同时也提高了可读性,而不是多行lambda。也许您可以使用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 isVisible = set.contains(elementId);
可能正在将流中的C映射为null,然后在null时返回true?像这样:
mappings.stream().map(a -> a instanceof C ? (B)null : (B)a)
.collect(Collectors.toMap(A::getId, m==null || m.isVisible()));
如果无法更改源代码,则可以编写实用程序方法
isA
来描述所需内容,例如:
Map<Integer, Boolean> visibility = mappings.stream().collect(toMap(
A::getId,
isA(B.class, B::isVisible, any -> true)
));
Map visibility=mappings.stream().collect(toMap(
A::getId,
isA(B.class,B::isVisible,any->true)
));
静态函数isA(类您的变体
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));
然后,根据经验,只要在复合布尔表达式中有布尔值
文本,就有一种没有它的替代方法
mappings.stream()
.collect(Collectors.toMap(A::getId, m -> !(m instanceof B) || ((B)m).isVisible()));
类A包含getId
方法,还是我错了?@OlimpiuPOP那么你为什么调用B::getId
?你的例子有点让人困惑。在上一个lambda中,你命名了变量m
,但你使用的是映射实例B
。请检查你的例子以避免与你的问题无关的问题。还有de>.filter(a->instanceof B)
可能应该是.filter(a->a instanceof B)
您应该能够减少m->{boolean isB=m instanceof B;返回isB?((B)m)。isVisible():true;}
到m->m instanceof B?((B)m)。isVisible():true
(尽管还不清楚这是否是您想要的).说真的-你所拥有的并不丑陋。你不会得到更好的建议。Pshemo是对的-这是你应该做的唯一一件事,以使你的代码更好…还有,这是如何比一个更简单的lambda表达式更好?我没有看到这一点的好处…我是从最初的问题出发的,而不是从现在提供的评论出发的一个简单的lambda表达式是的,我也这么认为,但我不能改变层次结构。谢谢首先,起来!我们是一样的。但是我用了一个实用方法来代替。嗨,梁!很好的方法,非常好functional@FedericoPeraltaSchaffner谢谢,你的回答激发了我的灵感。@FedericoPeraltaSchaffner你的记忆力很好。谢谢你记住我,我的朋友。:)请接受Federicoperalthaffner的答案,我的答案是从他的答案中得到启发的。但是你的答案要好得多,不需要帮助类m==null | | m.isVisible()
.map(a->a instanceof C?(B)null:(B)
应该是.map(a->a instanceof B?(B)a:(B)null)
还是我错了?@Eugene:也许值得发布一个包含所有组合的完整表格以供演示…@Eugene:不,不必要的复杂布尔表达式是一个反复出现的东西,不仅仅是在Stackoverflow上,所以我认为,这样一个表格,提醒开发人员更简单的替代方案,并证明我的特殊规则有效,也就是说,如果您在任何其他上下文中看到true
或false
而不是作为唯一常量,那么它应该总是会响起来,这可能有一些价值。好的,我同意。但那应该是一个单独的问答。。。如果你发布这样的帖子,我会更乐意投票——很可能甚至会将其导入我们的代码中base@Holger如果我要根据你的经验法则来实现声纳或FunBug的警报,我也会考虑常量谓词有效,即<代码> T->真< /代码>,我的意思是,除了boolean variable=true
@Federico Peralta Schaffner:这就是为什么我说“只要在复合布尔表达式中有布尔文字”。一个单独的文字不算数。简化规则甚至可以计算为布尔文字,例如a&&false
→ <代码>错误…
mappings.stream()
.collect(Collectors.toMap(A::getId, m ->
{
boolean isB = m instanceof B;
return isB ? ((B) m).isVisible() : true;
}));
mappings.stream()
.collect(Collectors.toMap(A::getId, m->m instanceof B? ((B)m).isVisible(): true));
mappings.stream()
.collect(Collectors.toMap(A::getId, m -> !(m instanceof B) || ((B)m).isVisible()));