Java 8 通过流连接字符串

Java 8 通过流连接字符串,java-8,Java 8,我正在尝试加入一个姓名列表: List<String> names; names = books.stream() .map( b -> b.getName() ) .filter( n -> ( (n != null) && (!n.isEmpty()) ) ) .collect(Collectors.joining(", ")); 有人能解释一下为什么吗?一些关于.map(b->b.getName())

我正在尝试加入一个姓名列表:

List<String> names;
names = books.stream()
        .map( b -> b.getName() )
        .filter( n -> ( (n != null) && (!n.isEmpty()) ) )
        .collect(Collectors.joining(", "));
有人能解释一下为什么吗?一些关于
.map(b->b.getName())
.map(Book::getName)
之间差异的说教性解释也很受欢迎,因为我认为我没有弄错。

连接(“,””收集器将收集所有字符串并使用给定的分隔符将其连接到单个字符串中。在本例中,
collect
的返回类型为
String
,但您正试图将结果分配给
列表
。如果要将字符串收集到列表中,请使用
Collectors.toList()

如果您有一个包含
Book
实例的集合,那么将
Book
s流映射到
String
s流一次就足够了

lamdba与方法参考的区别
  • lamdba表达式可以写为一个块,包含多个操作:

    b -> {
        // here you can have other operations
        return b.getName(); 
    }
    
    如果lambda有单次操作,则可以缩短:

    b -> b.getName()
    
  • 方法引用只是一个简单操作的lambda的“快捷方式”。这样:

    b -> b.getName()
    
    可替换为:

    Book::getName
    
    但是如果你有一个像这样的lambda:

    b -> b.getName().toLowerCase()
    
    您不能使用对
    getName
    方法的引用,因为您正在对
    toLowerCase()
    进行额外的调用


如果您使用的是Collectors.joining(),则结果将是单个串联字符串:

String names = books.stream()
        .map( b -> b.getName() )
        .filter(n -> (n != null) && !n.isEmpty())
        .collect(Collectors.joining(", "));
Collectors.toList()是返回列表的集合:

List<String> namesList = books.stream()
        .map( b -> b.getName() )
        .filter(n -> (n != null) && !n.isEmpty())
        .collect(Collectors.toList());
您还可以将此方法(不在
书籍
类中)作为参数传递给
map()
方法:

String names = books.stream()
            .map(this::getReducedBookName)
            .filter(n -> !n.isEmpty())
            .collect(Collectors.joining(", "));
如果您更喜欢
映射
而不是
映射

作为
字符串

String names = books.stream().collect(mapping(Book::getName,
    filtering(s -> s != null && ! s.isBlank(),
      joining(", "))));
作为
列表

List<String> names = books.stream().collect(mapping(Book::getName,
    filtering(s -> s != null && ! s.isBlank(),
      toList())));
List name=books.stream().collect(映射(Book::getName,
筛选(s->s!=null&&!s.isBlank(),
toList());

好了,我现在明白我的愚蠢错误了。在Book::getName上使用b->b.getName()会有什么影响?方法引用可能会稍微高效一些,但实际上效率很低,所以这不应该影响设计决策。另一点是,
Book::getName
引用声明类,因此,有时在使用
b->b.getName()
时编译器无法推断
b
的类型的情况下工作,尽管这也可以通过使用
(Book b)->b.getName()来解决
then.Method引用也可能是危险的:你真的认为这样多的括号(
.filter(n->)((n!=null)&&&(!n.isEmpty()))
比直接的
.filter(n->n!=null&!n.isEmpty())提高了可读性吗
?嗯……我通常在任何时候使用括号,比如&&,只是为了清楚起见。在这种情况下,你是对的,它看起来很麻烦。我知道,
&&
|
之间的运算符优先级不是直观的答案,所以为了清楚起见,即使在不必要的地方,也要放括号。但是对于唯一的de>&运算符,无法错误解释该表达式。此外,还有另一个外括号对与逻辑表达式无关。由于您没有编写
b->(b.getName())
,因此在另一个表达式处有一个外括号对是不一致的。等等…
.map(b->b.getName()).map(Book::getName)
有效,但只有
.map(b->b.getName())
无效?因此
书籍
实际上不是
书籍
的集合?因此
b.getName()
返回一本
书籍
?可能这也是它不抱怨的原因。@user1156544,您应该在有问题的情况下编写它……这很混乱
String names = books.stream().collect(mapping(Book::getName,
    filtering(s -> s != null && ! s.isBlank(),
      joining(", "))));
List<String> names = books.stream().collect(mapping(Book::getName,
    filtering(s -> s != null && ! s.isBlank(),
      toList())));