The cleanest way to create a list in a functional way from a list of lists?

huangapple go评论64阅读模式
英文:

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&lt;DataObject&gt; dataObjectList = new ArrayList&lt;&gt;();
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

创建一个 StreamIterator,你需要首先创建一个 Iterable,然后使用 Iterable::spliterator 方法传递其 SpliteratorStreamSupport::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&lt;?&gt; 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&lt;Company&gt; iterable = () -&gt; companyRepository.findAll();
Stream&lt;Company&gt; 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&lt;DataObject&gt; dataObjectList = StreamSupport.stream(iterable.spliterator(), false)
		.flatMap(company -&gt; company.getEmployees().stream()
				.map(employee -&gt; {
					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&lt;DataObject&gt; dataObjectList = StreamSupport.stream(iterable.spliterator(), false)
		.flatMap(company -&gt; company.getEmployees().stream()
			.map(employee -&gt; 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&lt;DataObject&gt; dataObjectList = new ArrayList&lt;&gt;();

for (Company company : companyRepository.findAll()) {
    for (Employee employee : company.employees) {
        dataObjectList.add(new DataObject(company.getName(), employee.getName()));
    }
}

</details>



huangapple
  • 本文由 发表于 2020年8月28日 00:37:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/63620492.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定