使用谷歌番石榴收藏的怪异2.transform



我不完全确定给这个问题加上什么标题才能获得正确的头脑。这似乎是Java的轻描淡写,但它只发生在使用Guava Collections2.transform。转换器在迭代"结果"期间提供了我的对象的完全不同的实例,然后最终返回"结果"时包含的内容。因此,"setDateStamp(("实际上似乎不起作用,因为它是在似乎像幽灵一样出现和消失的实例上设置的。

当我实现 Collections2.transform(( 方法的逻辑等效项正在执行的操作(注释掉的代码(时,我得到了我期望的结果。我已经遍历了 google 代码、断点和所有内容,除了我的底层函数之外,没有通过任何方法创建新实例。

我明白他们的实现正在做什么:按需转换。不复杂。那么为什么这到底不起作用呢?

这是有问题的代码以及一些调试

@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}]

你对新对象的写入没有写入后备集合感到惊讶吗?

Collections.transform不只是"根据需要"进行转换 - 它根本不存储任何内容。 这就是"视图"在其文档中的含义。 每当您浏览 Collections2.transform ed 集合时,它都会再次应用该函数,并且是全新的。 一旦 apply 方法中的 for 循环用 result 完成,该对象就消失了;再也没有见过。

如果您想执行正在执行的操作,请在例如 ArrayList 中显式复制转换后的集合。

答案在javadoc中,但快速的答案是转换是懒惰的。返回的是旧集合的视图,每次访问元素时都会调用该函数;如果您只访问其中的几个,这将很有用。如果您知道要迭代多次,最好将视图复制到全新的集合中。

相关内容

  • 没有找到相关文章

最新更新