I need to add a custom method (which is a Consumer) to the dot chaining in stream api, i not sure how to do it, following is my code.
If that is not possible, is there anyway to do it with other operation? Maybe like with .map or something else?
fun main(args: Array<String>) {
var countries: List<String> = listOf("India", "Germany", "Japan")
var firstCountry = countries.stream()
.filter{it == "Germany"}
.performOperation{} //not sure what to do here
.findFirst()
println(firstCountry)
}
fun performOperation(country: String) {
if(country.length > 3) {
throw InvalidLengthException("Error")
}
//do some operation, won't return any value
doCustomOperation(country)
}
You may already be aware that when it comes to steams there are two types of operations, one is your map, filter etc. known as intermediate opeartion and others are terminal operations such as forEach. You said your custom operation wont return any value, hence making it a terminal operation. moreover it seems to me that you want to perform same operation for all the elements, basically a forEach. for this you can define an extension function on Stream as
fun <T> Stream<T>.someOperation(operation: (T) -> Unit){
this.forEach { operation(it) }
}
There is two ways to do what you want.
var firstCountry = countries.stream()
.filter{it == "Germany"}
.also(::performOperation)
.findFirst()
The :: is a function reference and is basically the same as .also { performOperation(it)}
The second one would be to make your own extension method on list. I wouldn't recommend it until you understand kotlin lambdas and extension methods
fun Stream<String>.performOperation(): Stream<String> {
for(country in this) {
if(country.length > 3) {
throw InvalidLengthException("Error")
}
doCustomOperation(country)
}
return this
}
You would just call that one like .performOperation() where you have the .performOperation{}
Related
Trying to call lambda provided by MyClass constructor using Kotlin Reflection.
data class MyClass(
var magic:Int=2,
var lambdaValue: ()->String = { //trying to call this lambda from reflection
"Working"
},
)
fun main(args: Array<String>) {
val clazz=MyClass::class
val obj=clazz.createInstance()
val kProperty=clazz.memberProperties
clazz.constructors.forEach{cons-> // for each construtor
cons.parameters.forEach{ parameter-> // looping through constructor parameters
val property=kProperty.find { it.name==parameter.name } // finding the exact property
print(parameter.name+" : ")
if(parameter.type.arguments.isEmpty()) // if empty Int,Float
{
println(property?.get(obj))
}else{
println(property?.call(obj)) // unable to call lambda
}
}
}
}
property.call(obj) returns Any which is not invokable. Any solution?
Expected:
magic : 2
lambdaValue : Working
Frankly speaking, I'm not sure what was your idea behind parameter.type.arguments.isEmpty(). It seems unrelated to what you try to do.
If we have a value of the property already, we can simply check its type and if its is a function then invoke it:
val value = kProperty.find { it.name==parameter.name }!!.get(obj)
print(parameter.name+" : ")
when (value) {
is Function0<*> -> println(value())
else -> println(value)
}
I think usefulness of such a code in generic case isn't very high. This code doesn't know what is the function and if it is going to return a value or perform some action, etc. Maybe in your specific case it is more useful.
I currently have a piece of logic as follows:
interface anotherRepository {
fun getThings(): Flow<List<String>>
}
interface repository {
suspend fun getSomeThings(): AsyncResult<SomeThings>
}
when (val result = repository.getSomeThings()) {
is AsyncResult.Success -> {
anotherRepository.getThings().collectLatest {
// update the state
}
else -> { }
}
}
The problem I am having is that, if repository.getSomeThings has been triggered multiple times before, anotherRepository.getThings is getting triggered for the amount of all the pre-loaded values from repository.getSomeThings. I was wondering what is the proper way to use these repositories, one a suspend function, the other a Flow together. The equivalent behaviour that is combineLatest{} in Rx.
Thank you.
There are a couple of ways to solve your problem. One way is just to call
repository.getSomeThings() in the collectLatest block and cache last result:
var lastResult: AsyncResult<SomeThings>? = null
anotherRepository.getThings().collectLatest {
if (lastResult == null) {
lastResult = repository.getSomeThings()
}
// use lastResult and List<String>
}
Another approach is to create a Flow, which will be calling repository.getSomeThings() function, and combine two Flows:
combine(
anotherRepository.getThings(),
flow {emit(repository.getSomeThings())}
) { result1: List<String>, result2: AsyncResult<SomeThings> ->
...
}
So I'm making regexes for collections (all quantifiers are possessive). It looks like this (keep in mind the example is overly simplified for readability's sake):
val mayBeAPerson: Boolean = "totally not a person"
.toList()
.matches { // this: PatternScope
one { it.isUpperCase() } // execution of lambda could end after this method
moreThan(0) { it.isLetter() }
one { it == ' ' }
lessThan(2) { // this: PatternScope
one { it.isUpperCase() }
one { it == '.' }
one { it == ' ' }
}
one { it.isUpperCase() }
moreThan(0) { it.isLetter() }
}
As you can see, execution of lambda passed to matches could end after first one, as the predicate passed to it doesn't match first character in List. And it indeed does end. However, my solution is the opposite of elegant, as it uses throwing an exception in one and catching it in matches.
fun List<Char>.matches(build: PatternScope.() -> Unit) = try {
val scope = PatternScope(iterator())
scope.build() // may throw MatchFailed
!scope.iterator.hasNext()
} catch (_: MatchFailed) {
false
}
class PatternScope(private val iterator: Iterator<Char>) {
inline fun one(predicate: (element: Char) -> Boolean) {
if (!iterator.hasNext() || !predicate(iterator.next())) {
throw MatchFailed("match failed")
}
}
.
. etc
.
}
It totally works, but I can't help but wonder: is there a better way? I do know throwing exceptions like this is just a fancy GOTO, and I could wrap all the methods of PatternScope in ifs, like this:
class PatternScope(private val iterator: Iterator<Char>) {
private var matchFailed = false
inline fun one(predicate: (element: Char) -> Boolean) {
if (!matchFailed) {
if (!iterator.hasNext() || !predicate(iterator.next())) {
matchFailed = true
}
}
}
inline fun moreThan(n: Int, predicate: (element: Char) -> Boolean) {
if (!matchFailed) {
// logic
}
}
.
. etc
.
}
Is it more elegant though? Now I'm invoking all the functions in lambda passed to matches, and I like it even less to be honest.
My real question is: is there even better way to do it? Some magic solution to return from lambda I don't even have real access to? Some non-local returns, but from functions lambda hasn't even see yet?
Can I return from lambda by invoking some function inside its body?
Edit
Just to clarify, let's say we have a lambda:
val lambda: () -> Unit = {
someMethod() // this should return from lambda (in some cases)
someOtherMethod() // this shouldn't be invoked
}
How should the body of someMethod look like, so that someOtherMethod does not even execute when the lambda is invoked? Is there any other way but making someMethod throw an exception and wrapping lambda in try-catch block like this:
try {
lambda() // throws
} catch (_: SomeThrowableIdk) { }
I don't see a better way, but please prove me wrong.
I assume you're actually using #PublishedApi since you have a private iterator and public inline functions that access it.
Since Kotlin doesn't have checked exceptions, it is against Kotlin convention to throw Exceptions for things that are not actually errors in the program (bugs). Your first approach feels a little hacky for this reason. Since your API has public inline functions, there's no way to totally encapsulate the exceptions. You could switch to non-inline functions and storing the steps in a collection to be run internally, but this is surely more runtime overhead than the inline functions or your second approach with if statements.
Your second approach is more like a typical builder, so I don't see the problem with it. Since your functions are inline, it's not like your compiled code has a bunch of unnecessary function calls. Just if statements. You could however add a helper function to clean up your code at all the sub-functions, though I'm not sure if this can extend to the complexity of your actual class:
class PatternScope(#PublishedApi internal val iterator: Iterator<Char>) {
#PublishedApi internal var matchFailed = false
#PublishedApi internal inline fun nextRequire(require: () -> Boolean) {
matchFailed = matchFailed || !require()
}
inline fun one(predicate: (element: Char) -> Boolean) = nextRequire {
iterator.hasNext() && predicate(iterator.next())
}
}
There's no way to do what you described in your edit. Non-local returns work only with lambdas. To support something like what you describe, Kotlin would need syntax for a special kind of function that has the ability to return from the function that calls it. A function like this would have to have a new kind of signature that also declares the return type of the type of function that is permitted to call it. There simply is no such syntax or function type like that in Kotlin.
I have a Flux of strings that should be converted to a Flux of dto. Parsing can be finished with an error and by the business rules I just need to skip such entries
If I use "Kotlin's" null - I got NPE because by design reactor doesn't accept nulls in .map
fun toDtoFlux(source:Flux<String>):Flux<Dto>{
source.map(Parser::parse)
.filter(it!=null)
}
object Parser{
fun parse(line:String):Dto?{
..
}
}
I can use Optional. But it is not a Kotlin way.
fun toDtoFlux(source:Flux<String>):Flux<Dto>{
source.map(Parser::parse)
.filter(Optional.isPresent)
.map(Optional::get)
}
object Parser{
fun parse(line:String):Optional<Dto>{
..
}
}
What is the most idiomatic way to handle such cases in Kotlin?
You can create an extension function:
fun <T, U> Flux<T>.mapNotNull(mapper: (T) -> U?): Flux<U> =
this.flatMap { Mono.justOrEmpty(mapper(it)) }
Then you can use it like this:
fun main() {
Flux.just("a", "b", "c")
.mapNotNull { someNullableMapFunction(it) }
.doOnNext { println(it) } // prints "a" and "c"
.blockLast()
}
fun someNullableMapFunction(it: String): String? {
if (it == "b") {
return null
}
return it
}
UPDATE
Based on Simon's comment extension function implementation might be more idiomatic (and performant?) in Reactor this way:
fun <T, U> Flux<T>.mapNotNull(mapper: (T) -> U?): Flux<U> =
this.handle { item, sink -> mapper(item)?.let { sink.next(it) } }
The solutions I see :
Using Reactor API
I'd suggest you to use Reactor API to address such case, and make your parser return a Mono. The empty Mono represents the absence of result. With that, you can use flatMap instead of chaining map/filter/map.
It may seem a little overkill like that, but it will allow any parser implementation to do async stuff in the future if needed (fetching information from third-party service, waiting validation from user, etc.).
And it also provide a powerful API to manage parsing errors, as you can define backoff/custom error policies on parsing result.
That would change your example like that :
fun interface Parser {
fun parse(record: String): Mono<Dto>;
}
fun Parser.toDtoFlux(source:Flux<String>): Flux<Dto> {
source.flatMap(this::parse)
}
Using sealed class
Kotlin offers other ways of managing result options, inspired by functional programming. One way is to use sealed classes to desing a set of common cases to handle upon parsing. It allows to model rich results, giving parser users multiple choices to handle errors.
sealed class ParseResult
class Success(val value: Dto) : ParseResult
class Failure(val reason : Exception) : ParseResult
object EmptyRecord : ParseResult
fun interface Parser {
fun parse(raw: String) : ParseResult
}
fun Parser.toDtoFlux(source:Flux<String>): Flux<Dto> {
return source.map(this::parse)
.flatMap { when (it) {
is Success -> Mono.just(it.value)
is Failure -> Mono.error(it.reason) // Or Mono.empty if you don't care
is EmptyRecord -> Mono.empty()
}}
}
Consider this:
fun readFiles(directory: String): List<File> {
val result = ArrayList<File>()
File(directory).walkTopDown().forEach {
result.addAll(getFiles(it))
}
return result
}
fun getFiles(file: File): List<File> { ... }
How can rewrite this so I don't need to initialize the result ArrayList but can directly return File(directory).walkTopDown().????
The question is not about what's the best way to read files or anything, just how I can write the above code more concise while doing the same.
You can use flatMap for this purpose. It first maps each element to a Sequence using your mapping function (so you kinda get a Sequence<Sequence<File>>), then it flattens every result back to a Sequence<File>.
Since walkTopDown returns a FileTreeWalk (which is a subclass of Sequence<File>), and you return a List<File>, you have to do some conversions as well. You can remove these conversions if you make getFiles and readFiles return a Sequence<File> instead.
fun readFiles(directory: String): List<File> {
return File(directory)
.walkTopDown()
.flatMap { getFiles(it).asSequence() }
.toList()
}