从 DTO 收集的智能数据收集
Smart data gathering from Collection of DTO
假设我们有一个包含一些字段的 ExampleDTO 列表,其中包括 "name" 字段。每次我想获得适当字段的列表时,在本例中为名称,我编写如下代码:
private List<String> getNames(List<ExampleDTO> exampleDTOs) {
List<String> names = new ArrayList<String>();
for (ExampleDTO exampleDTO : exampleDTOs)
names.add(exampleDTO.getName());
return names;
}
...但我也注意到这种代码一遍又一遍地重复
问题是:有什么聪明的方法可以帮助我减少产生的冗余代码量吗?
编辑:
我正在为我的应用程序使用 Java7
。
使用 Java 7 你可以使用 Guava 的 FluentIterable
and Function
:
List<ExampleDTO> exampleDTOs = ...;
List<String> names = FluentIterable.from(exampleDTOs)
.transform(new Function<ExampleDTO, String>() {
@Override
public String apply(ExampleDTO dto) {
return dto.getName();
}
})
.toList();
注意,虽然整个循环是用单个表达式表示的,但是性能明显比循环差很多,如果这样可读性更好,还是很有争议的。
我会坚持一个简单的循环,直到升级到 Java 8.
在其中一个项目中,我曾经用特殊注释标记所有此类循环,以便在执行升级到 Java 8 时很容易找到所有这些地方。
有了 Java 8 你可以使用 Streams API:
List<ExampleDTO> exampleDTOs = ...;
List<String> names = exampleDTOs.stream()
.map(dto -> dto.getName())
.collect(Collectors.toList());
如果您不一定需要 list 名称,它可能会变得更短 — 在这种情况下,可以删除 .collect(Collectors.toList())
部分。
例如,您可以直接在流上迭代姓名列表,如下所示:
exampleDTOs.stream()
.map(dto -> dto.getName())
.forEach(name -> System.out.println(name));
这只会打印所有名称,但您可以用其他任何内容替换 System.out.println(name)
。
在 java 8 中,你有一个名为 Function
的新接口,允许你映射一个值以获得其他东西,这里的想法是用 Java 实现相同的逻辑7.
所以函数接口将是:
public interface Function<T, R> {
/**
* Applies this function to the given argument.
* @param t the function argument
* @return the function result
*/
R apply(T t);
}
你的方法可能是这样的:
private <R> List<R> getValues(List<ExampleDTO> exampleDTOs, Function<ExampleDTO, R> function) {
List<R> values = new ArrayList<>();
for (ExampleDTO exampleDTO : exampleDTOs)
values.add(function.apply(exampleDTO));
return values;
}
在您的情况下,您可以使用 private static final 变量将您的函数定义为匿名函数 class,如下所示:
private static final Function<ExampleDTO, String> BY_NAME = new Function<ExampleDTO, String>() {
public String apply(ExampleDTO e) {
return e.getName();
}
}
然后调用 getValues(exampleDTOs, BY_NAME)
假设我们有一个包含一些字段的 ExampleDTO 列表,其中包括 "name" 字段。每次我想获得适当字段的列表时,在本例中为名称,我编写如下代码:
private List<String> getNames(List<ExampleDTO> exampleDTOs) {
List<String> names = new ArrayList<String>();
for (ExampleDTO exampleDTO : exampleDTOs)
names.add(exampleDTO.getName());
return names;
}
...但我也注意到这种代码一遍又一遍地重复
问题是:有什么聪明的方法可以帮助我减少产生的冗余代码量吗?
编辑:
我正在为我的应用程序使用 Java7
。
使用 Java 7 你可以使用 Guava 的 FluentIterable
and Function
:
List<ExampleDTO> exampleDTOs = ...;
List<String> names = FluentIterable.from(exampleDTOs)
.transform(new Function<ExampleDTO, String>() {
@Override
public String apply(ExampleDTO dto) {
return dto.getName();
}
})
.toList();
注意,虽然整个循环是用单个表达式表示的,但是性能明显比循环差很多,如果这样可读性更好,还是很有争议的。
我会坚持一个简单的循环,直到升级到 Java 8.
在其中一个项目中,我曾经用特殊注释标记所有此类循环,以便在执行升级到 Java 8 时很容易找到所有这些地方。
有了 Java 8 你可以使用 Streams API:
List<ExampleDTO> exampleDTOs = ...;
List<String> names = exampleDTOs.stream()
.map(dto -> dto.getName())
.collect(Collectors.toList());
如果您不一定需要 list 名称,它可能会变得更短 — 在这种情况下,可以删除 .collect(Collectors.toList())
部分。
例如,您可以直接在流上迭代姓名列表,如下所示:
exampleDTOs.stream()
.map(dto -> dto.getName())
.forEach(name -> System.out.println(name));
这只会打印所有名称,但您可以用其他任何内容替换 System.out.println(name)
。
在 java 8 中,你有一个名为 Function
的新接口,允许你映射一个值以获得其他东西,这里的想法是用 Java 实现相同的逻辑7.
所以函数接口将是:
public interface Function<T, R> {
/**
* Applies this function to the given argument.
* @param t the function argument
* @return the function result
*/
R apply(T t);
}
你的方法可能是这样的:
private <R> List<R> getValues(List<ExampleDTO> exampleDTOs, Function<ExampleDTO, R> function) {
List<R> values = new ArrayList<>();
for (ExampleDTO exampleDTO : exampleDTOs)
values.add(function.apply(exampleDTO));
return values;
}
在您的情况下,您可以使用 private static final 变量将您的函数定义为匿名函数 class,如下所示:
private static final Function<ExampleDTO, String> BY_NAME = new Function<ExampleDTO, String>() {
public String apply(ExampleDTO e) {
return e.getName();
}
}
然后调用 getValues(exampleDTOs, BY_NAME)