英文:
The cleanest way to create a list in a functional way from a list of lists?
问题
List<DataObject> dataObjectList = companyRepository.findAll().stream()
.flatMap(company -> company.getEmployees().stream()
.map(employee -> {
DataObject dataObject = new DataObject();
dataObject.setCompanyName(company.getName());
dataObject.setEmployeeName(employee.getName());
return dataObject;
}))
.collect(Collectors.toList());
英文:
I have the following code:
List<DataObject> dataObjectList = new ArrayList<>();
for (Company company : companyRepository.findAll()) {
for (Employee employee : company.employees) {
DataOjbect dataObject = new dataObject();
dataObject.setCompanyName(company.getName());
dataObject.setEmployeeName(employee.getName());
dataObjectList.add(dataObject);
}
}
What is the cleanest way to write this code in a functional style in java?
Note that companyRepository.findAll() returns an Iterator, so you can't simply create a stream out of it.
答案1
得分: 2
创建一个 Stream 从 Iterator,你需要首先创建一个 Iterable,然后使用 Iterable::spliterator 方法传递其 Spliterator 到 StreamSupport::stream。
Stream<?> stream = StreamSupport.stream(iterable.spliterator(), false);
Iterable 可以通过 lambda 表达式从 Iterator 创建,只要 Iterable 只有一个抽象方法,因此该接口适合这样的表达式。
Iterable<Company> iterable = () -> companyRepository.findAll();
Stream<Company> stream = StreamSupport.stream(iterable.spliterator(), false);
现在,事情变得简单:利用 flatMap 的优势来展平嵌套的列表结构(一个公司列表,每个公司都有一个员工列表)。你需要在 flatMap 方法内部创建每个 DataObject,只要它的实例化依赖于 company.getName() 参数:
List<DataObject> dataObjectList = StreamSupport.stream(iterable.spliterator(), false)
.flatMap(company -> company.getEmployees().stream()
.map(employee -> {
DataObject dataObject = new DataObject();
dataObject.setCompanyName(company.getName());
dataObject.setEmployeeName(employee.getName());
return dataObject;
}))
.collect(Collectors.toList());
... 使用构造函数则更简洁 ...
List<DataObject> dataObjectList = StreamSupport.stream(iterable.spliterator(), false)
.flatMap(company -> company.getEmployees().stream()
.map(employee -> new DataObject(company.getName(), employee.getName())))
.collect(Collectors.toList());
英文:
To create a Stream from Iterator, you need to create Iterable first and then pass its Spliterator using Iterable::spliterator method into StreamSupport::stream.
Stream<?> stream = StreamSupport.stream(iterable.spliterator(), false);
The Iterable can be created from Iterator through a lambda expression as long as Iterable has only one abstract method, therefore the interface is qualified for such expression.
Iterable<Company> iterable = () -> companyRepository.findAll();
Stream<Company> stream = StreamSupport.stream(iterable.spliterator(), false);
Now, the things get easy: Use the advantage of flatMap to flatten the nested list structure (a list of companies where each company has a list of employees. You need to create each DataObject right inside the flatMap method as long as its instantiation relies on the company.getName() parameter:
List<DataObject> dataObjectList = StreamSupport.stream(iterable.spliterator(), false)
.flatMap(company -> company.getEmployees().stream()
.map(employee -> {
DataObject dataObject = new DataObject();
dataObject.setCompanyName(company.getName());
dataObject.setEmployeeName(employee.getName());
return dataObject;
}))
.collect(Collectors.toList());
... and less verbose if you use a constructor ...
List<DataObject> dataObjectList = StreamSupport.stream(iterable.spliterator(), false)
.flatMap(company -> company.getEmployees().stream()
.map(employee -> new DataObject(company.getName(), employee.getName())))
.collect(Collectors.toList());
答案2
得分: 1
在我看来,使用流来完成这个任务实际上没有真正的好处。我建议你继续使用你目前的方法。你可以通过在你的DataObject类中创建一个constructor来使代码更加简洁。然后你可以这样做:
List<DataObject> dataObjectList = new ArrayList<>();
for (Company company : companyRepository.findAll()) {
for (Employee employee : company.employees) {
dataObjectList.add(new DataObject(company.getName(), employee.getName()));
}
}
英文:
Imo, there is no real benefit to using streams to do this. I would stick with what you have. You could make it more concise by creating a constructor in your DataObject class. Then you could do the following:
List<DataObject> dataObjectList = new ArrayList<>();
for (Company company : companyRepository.findAll()) {
for (Employee employee : company.employees) {
dataObjectList.add(new DataObject(company.getName(), employee.getName()));
}
}
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论