我并不完全确定在这个问题上能够获得正确思想的标题。这看起来像Java一样,但它只是使用Guava Collections2.transform。变换器在迭代“结果”期间提供完全不同的对象实例,然后在“结果”最终返回时包含的内容。因此,'setDateStamp()'实际上看起来并不起作用,因为它被设置在似乎刚出现并像鬼一样消失的实例上。
当我实现Collections2.transform()方法的逻辑等价物(注释掉代码)时,我得到了我期望的结果。我已经介绍了谷歌代码,断点和所有内容,并且没有通过除基础函数之外的任何方法创建新实例的位置。
我得到了他们的实现正在做的事情:根据需要进行转换。不复杂。那么为什么地狱不起作用呢?
这是有问题的代码以及一些调试
@Component
public class SurveyResultToQuestionResults implements Function<SurveyResult, Collection<QuestionResult>> {
@Autowired
private QuestionResultDtoToDomain dtoToDomain;
@Override
public Collection<QuestionResult> apply(@Nullable SurveyResult input) {
Collection<QuestionResult> results = new HashSet<QuestionResult>();
if (input != null) {
// substitute this
// for (QuestionResultDto dto : input.getResults()) {
// QuestionResult result = dtoToDomain.apply(dto);
// results.add(result);
// }
// for this
results = Collections2.transform(input.getResults(), dtoToDomain);
for (QuestionResult result : results) {
long time = input.getSurveyTime().getTime();
Timestamp dateStamp = new Timestamp(time);
result.setDateStamp(dateStamp);
}
}
return results;
}
}
下一堂课
@Component
public class QuestionResultDtoToDomain implements Function<QuestionResultDto, QuestionResult> {
@Override
public QuestionResult apply(@Nullable QuestionResultDto input) {
QuestionResult result = null;
if (input != null)
result = new QuestionResult(input.getAnswerOriginId(),input.getAnswer(),input.getQuestionId());
return result;
}
}
并进行测试
@RunWith(MockitoJUnitRunner.class)
public class SurveyTransformerTest {
@Spy
private QuestionResultDtoToDomain dtoToDomain = new QuestionResultDtoToDomain();
@InjectMocks
private SurveyResultToQuestionResults surveyResultToQuestionResults = new SurveyResultToQuestionResults();
@Test
public void testSurveyToQuestionResults() throws Exception {
Set<QuestionResultDto> answers = new HashSet<QuestionResultDto>();
answers.add(new QuestionResultDto(17L,"question 2 answer"));
answers.add(new QuestionResultDto(18L,"question 3 answer"));
answers.add(new QuestionResultDto(19L,"question 4 answer"));
SurveyResult result = new SurveyResult(10L,16L,new Date(),answers);
Collection<QuestionResult> qresults = surveyResultToQuestionResults.apply (result);
System.out.println(qresults);
for (QuestionResult qresult : qresults) {
assertNotNull(qresult.getDateStamp());
}
}
}
Debug:
Bad implementation
[QuestionResult{questionResultId=null, answer='question 4 answer', dateStamp=null}, QuestionResult{questionResultId=null, answer='question 2 answer', dateStamp=null}, QuestionResult{questionResultId=null, answer='question 3 answer', dateStamp=null}]
Good implementation:
[QuestionResult{questionResultId=null, answer='question 4 answer', dateStamp=2012-05-17 00:02:18.615}, QuestionResult{questionResultId=null, answer='question 3 answer', dateStamp=2012-05-17 00:02:18.615}, QuestionResult{questionResultId=null, answer='question 2 answer', dateStamp=2012-05-17 00:02:18.615}]
答案 0 :(得分:9)
您对新对象的写入没有写入后台集合感到惊讶吗?
Collections.transform
不仅仅根据需要进行转换 - 它根本不存储任何内容。这就是“视图”在其文档中的含义。每当您浏览Collections2.transform
ed集合时,它都会再次应用 功能。在使用apply
完成result
方法中的for循环之后,该对象就消失了;从未见过。
如果您想要做您正在做的事情,请在转换的集合中制作一个明确的副本。 ArrayList
。
答案 1 :(得分:3)
答案在javadoc,但快速回答是变换是懒惰的。返回的是旧集合的视图,每次访问元素时都会调用该函数;如果您只访问其中的一些,这将非常有用。如果您知道要多次迭代,最好将视图复制到一个全新的Collection中。