如何在 Kotlin 的 try-with-resources 块中使用 Spring Data JPA 方法返回 Stream?

How to use Spring Data JPA methods returning a Stream in a try-with-resources block in Kotlin?

所以我想使用 Kotlin 创建一个 Spring BootSpring Data JPA 项目,假设我有一个 Person 实体。让我们这样说:

@Entity
public class Person {

   private @GeneratedValue @Id Long id;
   private String name;

   @OneToMany
   private List<Person> friends;

   …
}

我将创建以下界面以便能够使用 Try-with-ResourcesStream<Person>

public interface PersonRepository extends Repository<Person, Long> {

    @Query("select p from Person p")
    Stream<Person> findAllStream();
}

所以通常在我的服务中我会这样做:

@Service
class MyService {

    @Autowired PersonRepository repository;

    List<String> foo() {

       try(Stream<Person> stream = repository.findAllStream()) {
          return stream.flatMap(p -> p.getFriends().stream())
             .map(f -> f.getName())
             .collect(Collectors.toList());
       }
    }
 }

现在,如果您想在 Kotlin 中执行此操作(IntelliJ 转换器不会生成有效代码)。我想你通常会做这样的事情:

class MyService @Autowired constructor(val personRepository: PersonRepository) {
    fun foo() {
        val list = personRepository.findAllStream()
                       .use {{p -> p.friends.stream()}.map {f -> f.name}}
    }
}

只有你不能这样做,因为流中没有 #use 方法,你不能从 List 调用 #stream()。那么有没有办法做到这一点?

好吧,Java Kotlin 对 8 的支持尚未完成。所以你可以像这样在你这边声明使用

inline fun <A : AutoCloseable, R> A.use(block: (A) -> R): R {
    try {
        return block(this)
    } finally {
        close()
    }
}

另一种选择是直接在 Stream

上声明它
inline fun <T, R> Stream<T>.use(block: (Stream<T>) -> R): R {
    try {
        return block(this)
    } finally {
        close()
    }
}

UPD

如果您是 Kotlin 的新手,您必须注意扩展是静态解析的:

Extensions do not actually modify classes they extend. By defining an extension, you do not insert new members into a class, but merely make new functions callable with the dot-notation on instances of this class.

查看更多http://kotlinlang.org/docs/reference/extensions.html#extensions-are-resolved-statically