在 java8 中累积对的功能方法
functional way to accumulate pairs in java8
下面是一些命令式代码,我正在尝试将其转换为函数式编程代码:
public class Person {
String name;
Token token;
public Person(String name, Token token) {
this.name = name;
this.token = token;
}
}
public class Token {
String id;
boolean isValid;
public Token(String id, boolean isValid) {
this.id = id;
this.isValid = isValid;
}
public String getId() { return id; }
public boolean isValid() {return isValid;}
}
public static List<Token> getTokensForPerson(String name) {...}
public static List<Person> getPeople1 (String[] names) {
List<Person> people = new ArrayList<Person> ();
for (String name: names) {
List<Token> tokens = getTokensForPerson(name);
for (Token token: tokens) {
if (token.isValid()) {
people.add(new Person(name, token));
}
}
}
return people;
}
这是我尝试以功能方式进行的尝试。
public static List<Person> getPeople2 (String[] names) {
return Arrays.stream(names).map(name -> getTokensForPerson(name))
.flatMap(tokens -> tokens.stream().filter(token -> token.isValid))
.map(token -> new Person(name, token)) // <== compiler error here. "Cannot resolve symbol 'name'"
.collect(Collectors.toList());
}
但是它无法编译,因为在上次映射操作中我需要参考 name
来创建 Person
对象,而当时 name
不可用。有什么想法吗?
您可以将 map
步骤移动到 flatMap
:
return Arrays.stream(names)
.<Person>flatMap(
name -> getTokensForPerson(name).stream()
.filter(Token::isValid)
.map(token -> new Person(name, token)))
.collect(Collectors.toList());
这样您也可以访问 name
变量。
基于StreamEx的解决方案更短,但它需要第三方库:
return StreamEx.of(names)
.cross(name -> getTokensForPerson(name).stream())
// Here we have the stream of entries
// where keys are names and values are tokens
.filterValues(Token::isValid)
.mapKeyValue(Person::new)
.toList();
是否可以创建 TokenExtended
class 扩展令牌,并添加名称,并且 return 来自 getTokensForPerson 的 List<TokenExtended>
而不是 List<Token>
?
public class TokenExtended extends Token {
private String name;
public TokenExtended(String name, String id, boolean isValid) {
super(id, isValid);
this.name = name;
}
}
这样你的代码就可以工作了
Arrays.stream(names).map(name -> getTokensForPerson(name)).flatMap(tokens -> tokens.stream().filter(token -> token.isValid))
.map(token -> new Person(token.name, token)).collect(Collectors.toList());
下面是一些命令式代码,我正在尝试将其转换为函数式编程代码:
public class Person {
String name;
Token token;
public Person(String name, Token token) {
this.name = name;
this.token = token;
}
}
public class Token {
String id;
boolean isValid;
public Token(String id, boolean isValid) {
this.id = id;
this.isValid = isValid;
}
public String getId() { return id; }
public boolean isValid() {return isValid;}
}
public static List<Token> getTokensForPerson(String name) {...}
public static List<Person> getPeople1 (String[] names) {
List<Person> people = new ArrayList<Person> ();
for (String name: names) {
List<Token> tokens = getTokensForPerson(name);
for (Token token: tokens) {
if (token.isValid()) {
people.add(new Person(name, token));
}
}
}
return people;
}
这是我尝试以功能方式进行的尝试。
public static List<Person> getPeople2 (String[] names) {
return Arrays.stream(names).map(name -> getTokensForPerson(name))
.flatMap(tokens -> tokens.stream().filter(token -> token.isValid))
.map(token -> new Person(name, token)) // <== compiler error here. "Cannot resolve symbol 'name'"
.collect(Collectors.toList());
}
但是它无法编译,因为在上次映射操作中我需要参考 name
来创建 Person
对象,而当时 name
不可用。有什么想法吗?
您可以将 map
步骤移动到 flatMap
:
return Arrays.stream(names)
.<Person>flatMap(
name -> getTokensForPerson(name).stream()
.filter(Token::isValid)
.map(token -> new Person(name, token)))
.collect(Collectors.toList());
这样您也可以访问 name
变量。
StreamEx的解决方案更短,但它需要第三方库:
return StreamEx.of(names)
.cross(name -> getTokensForPerson(name).stream())
// Here we have the stream of entries
// where keys are names and values are tokens
.filterValues(Token::isValid)
.mapKeyValue(Person::new)
.toList();
是否可以创建 TokenExtended
class 扩展令牌,并添加名称,并且 return 来自 getTokensForPerson 的 List<TokenExtended>
而不是 List<Token>
?
public class TokenExtended extends Token {
private String name;
public TokenExtended(String name, String id, boolean isValid) {
super(id, isValid);
this.name = name;
}
}
这样你的代码就可以工作了
Arrays.stream(names).map(name -> getTokensForPerson(name)).flatMap(tokens -> tokens.stream().filter(token -> token.isValid))
.map(token -> new Person(token.name, token)).collect(Collectors.toList());