我想加入一个名单:
List<String> names;
names = books.stream()
.map( b -> b.getName() )
.filter( n -> ( (n != null) && (!n.isEmpty()) ) )
.collect(Collectors.joining(", "));
这不会编译说:
不兼容的类型。推理变量R具有不兼容的边界
经过一些研究,似乎有些事我误解了。我认为.map( b -> b.getName() )
返回/将类型更改为String,看起来似乎有些问题。如果我使用.map(Book::getName)
代替,我仍然会收到错误,但我可能会don't fully understand the difference。
然而,这并没有抱怨:
List<String> names;
names = books.stream()
.map( b -> b.getName() )
.map( Book::getName )
.filter( n -> ( (n != null) && (!n.isEmpty()) ) )
.collect(Collectors.joining(", "));
有人可以解释我为什么吗?关于.map( b -> b.getName() )
和.map(Book::getName)
之间差异的一些教学解释也很受欢迎,因为我认为我没有做对。
答案 0 :(得分:7)
joining(", ")
收藏家将使用传递的字符串收集加入所有字符串到单个字符串。在这种情况下,collect
的撤销类型为String
,但您尝试将结果分配给List
。
如果要收集字符串列表,请使用Collectors.toList()
。
如果您有Book
个实例的集合,那么您就足以将Book
的流映射到String
的流一次。
lamdba通常有一个运营商块:
b -> {
// here can be other operators
return b.getName(); // single operator
}
如果lambda有单个运算符,则可以缩短它:
b -> b.getName()
方法参考只是&#34;快捷方式&#34;对于具有单个运算符的lambda:
b -> b.getName()
可以替换为
Book::getName
但如果你有这样的lambda:
b -> b.getName().toLowerCase()
这里你不能引用getName
方法,因为你需要做额外的电话。
答案 1 :(得分:3)
如果您使用的是Collectors.joining(),则结果将是单个串联字符串:
String names = books.stream()
.map( b -> b.getName() )
.filter(n -> (n != null) && !n.isEmpty())
.collect(Collectors.joining(", "));
Collectors.toList()是返回List的那个:
List<String> names = books.stream()
.map( b -> b.getName() )
.filter(n -> (n != null) && !n.isEmpty())
.collect(Collectors.toList());
Book::getName
是method reference,其结果与b -> b.getName()
相同。方法引用更清晰,只要传递的方法符合预期functional interface的签名,就可以将其他现有方法作为参数传递给map()
等方法。在这种情况下,map()
需要Function接口的实例。因此,您可以从这样的接口提供符合抽象R apply(T t)
方法签名的方法的任何引用。
由于您要将Book
映射到String
,因此要为map()
方法提供的方法的实际签名必须为String apply(Book t)
。这可以理解为“接收书籍并返回字符串”。这样,您传递的任何符合此定义的方法都是有效的。当您传递方法引用Book::getName
时,getName
方法本身不符合上面提供的签名(因为它根本没有参数),但它符合此类签名的定义: 您传递一本书并从其名称返回一个字符串。
因此,请考虑一下,在您拥有图书清单的班级中,您还有一个方法可以对Book
执行任何操作,并返回String
。下面的方法是一个示例,它接收Book
并从其名称中获取前10个字符:
public String getReducedBookName(Book b){
if(b.getName() == null)
return "";
String name = b.getName();
return name.substring(0, name.length() > 10 ? 10 : name.length());
}
您也可以将此方法(不在Book
类中)作为参数传递给map()
方法:
String names = books.stream()
.map(this::getReducedBookName)
.filter(n -> !n.isEmpty())
.collect(Collectors.joining(", "));
答案 2 :(得分:0)
如果你喜欢 mapping
over map
作为String
String names = books.stream().collect(mapping(Book::getName,
filtering(s -> s != null && ! s.isBlank(),
joining(", "))));
作为List
List<String> names = books.stream().collect(mapping(Book::getName,
filtering(s -> s != null && ! s.isBlank(),
toList())));