I came across the following code:
import io.reactivex.Observable
import io.reactivex.functions.BiFunction
import java.util.concurrent.TimeUnit
class ExpBackoff(
private val jitter: Jitter,
private val delay: Long,
private val unit: TimeUnit,
private val retries: Int = 0
) : Function<Observable<out Throwable>, Observable<Long>> {
#Throws(Exception::class)
override fun apply(observable: Observable<out Throwable>): Observable<Long> {
return observable
.zipWith(Observable.range(1, retries), BiFunction<Throwable, Int, Int> { _, retryCount ->
retryCount
})
.flatMap { attemptNumber -> Observable.timer(getNewInterval(attemptNumber), unit) }
}
private fun getNewInterval(retryCount: Int): Long {
var newInterval = (delay * Math.pow(retryCount.toDouble(), 2.0) * jitter.get()).toLong()
if (newInterval < 0) {
newInterval = Long.MAX_VALUE
}
return newInterval
}
}
located at:
https://leandrofavarin.com/exponential-backoff-rxjava-operator-with-jitter
This code doesn't compile. This line is wrong:
Function<Observable<out Throwable>, Observable<Long>>
Function only takes a single argument. I am really confused here. The person who wrote the article clearly indicates that he wrote this code and I assume it works or at least worked at the time he wrote it. But I doubt that Kotlin changed the interface for Function. Even if I remove the second parameter, the code will not compile because the apply function cannot be overridden as this is not part of the Function interface.
How can I fix this issue?
Looks like you are missing correct Function import. The following code works in my IDE.
import io.reactivex.Observable
import io.reactivex.functions.BiFunction
import io.reactivex.functions.Function
import java.util.concurrent.TimeUnit
class ExpBackoff(
private val jitter: Jitter,
private val delay: Long,
private val unit: TimeUnit,
private val retries: Int = 0
) : Function<Observable<out Throwable>, Observable<Long>> {
#Throws(Exception::class)
override fun apply(observable: Observable<out Throwable>): Observable<Long> {
return observable
.zipWith(Observable.range(1, retries), BiFunction<Throwable, Int, Int> { _, retryCount ->
retryCount
})
.flatMap { attemptNumber -> Observable.timer(getNewInterval(attemptNumber), unit) }
}
private fun getNewInterval(retryCount: Int): Long {
var newInterval = (delay * Math.pow(retryCount.toDouble(), 2.0) * jitter.get()).toLong()
if (newInterval < 0) {
newInterval = Long.MAX_VALUE
}
return newInterval
}
}
Related
I want to be able to call functions from the anonymous constructor's suspend function in the following example:
data class SuspendableStep(
val condition: SuspendableCondition,
val continuation: Continuation<Unit>
)
class WaitCondition(cycles: Int) : SuspendableCondition() {
private val timer = SomeTimer(cycles)
override fun resume(): Boolean = timer.elapsed() // timer is handled somewhere else
override fun toString(): String = "WaitCondition_$timer"
}
class BasicContinuation : Continuation<Unit> {
var coroutine: Continuation<Unit>
override val context: CoroutineContext = EmptyCoroutineContext
private var nextStep: SuspendableStep? = null
constructor(task: suspend () -> Unit) {
coroutine = task.createCoroutine(completion = this)
}
override fun resumeWith(result: Result<Unit>) {
nextStep = null
result.exceptionOrNull()?.let { e -> Logger.handle("Error with plugin!", e) }
}
suspend fun wait(cycles: Int): Unit = suspendCoroutine {
check(cycles > 0) { "Wait cycles must be greater than 0." }
nextStep = SuspendableStep(WaitCondition(cycles), it)
}
}
fun main() {
BasicContinuation({
println("HELLO")
wait(1)
println("WORLD")
}).coroutine.resume(Unit)
}
There only other option I found was to override a suspend function by creating an anonymous inner class and calling another function to set the coroutine:
fun main() {
val bc = BasicContinuation() {
override suspend fun test() : Unit {
println("HELLO")
wait(1)
println("WORLD")
}
}
bc.set() // assign coroutine to suspend { test }.createCoroutine(completion = this)
bc.coroutine.resume(Unit)
}
I used CoroutineScope to extend the scope of the functions I could access:
class BasicContinuation : Continuation<Unit> {
var coroutine: Continuation<Unit>
override val context: CoroutineContext = EmptyCoroutineContext
private var nextStep: SuspendableStep? = null
constructor(task: (suspend BasicContinuation.(CoroutineScope) -> Unit)) {
coroutine = suspend { task.invoke(this, CoroutineScope(context)) }.createCoroutine(completion = this)
}
override fun resumeWith(result: Result<Unit>) {
nextStep = null
result.exceptionOrNull()?.let { e -> Logger.handle("Error with plugin!", e) }
}
suspend fun wait(cycles: Int): Unit = suspendCoroutine {
check(cycles > 0) { "Wait cycles must be greater than 0." }
nextStep = SuspendableStep(WaitCondition(cycles), it)
}
}
fun main() {
val bc = BasicContinuation({
println("Hello")
wait(1)
println("World")
})
bc.coroutine.resume(Unit) // print "Hello"
// increment timer
bc.coroutine.resume(Unit) // print "World
}
I have been trying to upload multiple images to Firebase Storage. But, I am not able to do it successfully. I could successfully upload the image (single) to the storage and add the URL of the image to the Firestore, now that I revised my code to upload up to five images, it could be any number of images from 1 to 5.
R.id.btn_submit -> {
if (validateDetails()) {
uploadImage()
}
}
The above code, calls the following function after validating the fields, which then calls the function uploadImageToCloudStorage. mSelectedImageFileUriList is private var mSelectedImageFileUriList: MutableList<Uri?>? = null. It all seems to work correctly.
private fun uploadImage() {
showProgressDialog(resources.getString(R.string.please_wait))
FirestoreClass().uploadImageToCloudStorage(
this#AddProductActivity,
mSelectedImageFileUriList,
Constants.PRODUCT_IMAGE,
Constants.PRODUCT_IMAGE_DIRECTORY_NAME,
et_product_title.text.toString().trim { it <= ' ' }
)
}
Following code is where I guess is a mistake.
fun uploadImageToCloudStorage(
activity: AddProductActivity,
imageFileURI: MutableList<Uri?>?,
imageType: String,
directoryName: String,
title: String
) {
var i = 0
val imageURLList = ArrayList<String>()
val itr = imageFileURI?.iterator()
if (itr != null) {
while (itr.hasNext()) {
val sRef: StorageReference = FirebaseStorage.getInstance().getReference(
"/$directoryName/" + imageType + "." + Constants.getFileExtension(
activity,
imageFileURI[i]
)
)
sRef.putFile(imageFileURI[i]!!)
.addOnSuccessListener { taskSnapshot ->
taskSnapshot.metadata!!.reference!!.downloadUrl
.addOnSuccessListener { uri ->
if (i < imageFileURI.size) {
i += 1
imageURLList.add(uri.toString())
} else {
activity.imageUploadSuccess(imageURLList)
}
}
}
.addOnFailureListener { exception ->
activity.hideProgressDialog()
Log.e(
activity.javaClass.simpleName,
exception.message,
exception
)
}
}
} else {
Toast.makeText(
activity,
"There is no images in the ArrayList of URI",
Toast.LENGTH_SHORT
).show()
}
}
EDIT: After receiving the first answer.
I have created a QueueSyn.kt file and added the code in the Answer. The activity where the images and the button are changed to
class AddProductActivity : BaseActivity(), View.OnClickListener, QueueSyncCallback {
The following function is called when the button is hit.
private fun uploadProductImage() {
showProgressDialog(resources.getString(R.string.please_wait))
QueueSync(
mSelectedImageFileUriList,
Constants.PRODUCT_IMAGE,
Constants.PRODUCT_IMAGE_DIRECTORY_NAME,
et_product_title.text.toString().trim { it <= ' ' },
this
).startUploading()
}
I have also implemented these two methods in the class AddProductActivity, but I don't know what should go inside this.
override fun completed(successList: MutableList<Uri>, failureList: MutableList<Uri>) {
TODO("Not yet implemented")
}
override fun getFileExtension(uri: Uri): String {
TODO("Not yet implemented")
}
Error:
This should work
import android.net.Uri
import com.google.firebase.storage.FirebaseStorage
import com.google.firebase.storage.StorageReference
import java.util.*
import kotlin.collections.ArrayList
interface QueueSyncCallback {
fun completed(successList: MutableList<Uri>, failureList: MutableList<Uri>)
fun getFileExtension(uri: Uri): String
}
class QueueSync(
imageFileURI: MutableList<Uri?>?,
private val imageType: String,
private val directoryName: String,
private val title: String,
private val callback: QueueSyncCallback,
private val maxActive: Int = 5
) {
private val queue: LinkedList<Uri> = LinkedList()
private val runningQueue: MutableList<Uri> = Collections.synchronizedList(
object : ArrayList<Uri>() {
override fun remove(element: Uri): Boolean {
val removed = super.remove(element)
if (isEmpty() && queue.isEmpty()) {
callback.completed(successList, failureList)
} else if (queue.isNotEmpty()) {
addToRunningQueue()
}
return removed
}
}
)
private val successList: MutableList<Uri> = Collections.synchronizedList(ArrayList())
private val failureList: MutableList<Uri> = Collections.synchronizedList(ArrayList())
init {
if (imageFileURI != null)
for (uri in imageFileURI) {
if (uri != null)
queue.add(uri)
}
}
private fun getLocation(uri: Uri) = "/$directoryName/$imageType.${callback.getFileExtension(uri)}"
fun startUploading() {
var i = 0
if (queue.isEmpty()) {
callback.completed(successList, failureList)
return
}
while (i < maxActive && queue.isNotEmpty()) {
addToRunningQueue()
i++
}
}
private fun addToRunningQueue() {
val uri = queue.poll()!!
runningQueue.add(uri)
uploadImageToCloudStorage(uri)
}
private fun uploadImageToCloudStorage(locationUri: Uri) {
val sRef: StorageReference = FirebaseStorage.getInstance().getReference(getLocation(locationUri))
sRef.putFile(locationUri)
.addOnSuccessListener { taskSnapshot ->
taskSnapshot.metadata!!.reference!!.downloadUrl
.addOnSuccessListener { uri ->
successList.add(uri)
runningQueue.remove(locationUri)
}
}
.addOnFailureListener {
failureList.add(locationUri)
runningQueue.remove(locationUri)
}
}
}
Since your need requires usage of threads so to prevent race conditions I had to use Collections.synchronizedList. To use this you need to implement QueueSyncCallback in your activity and pass it as a reference to QueueSync. Make sure that any piece of code written inside completed is wrapped inside runOnMainThread if it is going to access views in any way since completed will not run on main thread as far as I know. This should work however I am not able to test it since it is based on your current code.
Edit:- Answering after edit
override fun completed(successList: MutableList<Uri>, failureList: MutableList<Uri>) {
imageUploadSuccess(successList)
hideProgressDialog()
}
override fun getFileExtension(uri: Uri): String {
Constants.getFileExtension(this, imageFileURI[i])
}
I'm working on a Kotlin Multiplatform project. And I'm trying to use a timer and countdown timer but I cannot access kotlin.concurrent.fixedRateTimer or import kotlin.concurrent.timer in commonMain module.
However the kotlin.concurrent is available:
This is root build.gradle :
plugins {
kotlin("multiplatform")
id("com.android.library")
id("kotlin-android-extensions")
}
// ...
kotlin {
//...
sourceSets {
val commonMain by getting {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.4.10")
implementation("org.jetbrains.kotlin:kotlin-reflect:1.4.10")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9")
//...
}
}
//...
}
}
I wonder if it's even possible to use these methods there. If not, how can I write a timer and countdown timer in commonMain module?
I have tried to use Coroutines to achieve the same functionality but failed because they are not precise:
fun doAfter(delay: Long, action: () -> (Unit)) = launch {
delay(delay)
action.invoke()
}
fun countdown(time: Long, tick: Long, onTick: () -> (Unit), onFinish: () -> (Unit)) = launch {
val ticks = (time / tick).toInt()
repeat(ticks) {
onTick()
delay(tick)
}
onFinish()
}
As said by Qaz, the function you are trying to use in common code is JVM only.
Usually in KMP, when you still don't have a common functionality already built in by the framework you could follow different approaches:
Use someone else library (e.g. moko-time) - Best place for searching libraries is here.
Use the native framworks classes by the expect/actual mechanism
Just to give you and example of what could be done (not sure if that is right for you or could fit your needs. It's just to put you in the right direction and above all what I've wrote could not be production ready at all [-;)
commonMain:Timer.kt
expect class KMMTimer(
name: String? = null,
interval: Long,
delay: Long,
action: () -> Unit
) {
val name: String?
val interval: Long
val delay: Long
fun start()
fun cancel()
fun isRunning(): Boolean
}
androidMain:Timer.kt
import java.util.*
import kotlin.concurrent.fixedRateTimer
actual class KMMTimer actual constructor(
actual val name: String?,
actual val interval: Long,
actual val delay: Long,
action: () -> Unit
) {
private var timer: Timer? = null
private val action = action
actual fun start() {
if (!isRunning()) {
timer = fixedRateTimer(
name = name,
initialDelay = delay,
period = interval
) {
action()
}
}
}
actual fun cancel() {
timer?.cancel()
timer = null
}
actual fun isRunning(): Boolean {
return timer != null
}
}
iosMain:Timer.kt
import platform.Foundation.NSDate
import platform.Foundation.NSRunLoop
import platform.Foundation.NSRunLoopCommonModes
import platform.Foundation.NSTimer
actual class KMMTimer actual constructor(
actual val name: String?,
actual val interval: Long,
actual val delay: Long,
action: () -> Unit
) {
private var timer: NSTimer? = null
private var action = action
actual fun start() {
if (!isRunning()) {
timer = NSTimer(
fireDate = NSDate(
NSDate().timeIntervalSinceReferenceDate + (delay.toDouble() / 1000)
),
interval = (interval.toDouble() / 1000),
repeats = true,
block = {
action()
}
)
timer?.let {
NSRunLoop.currentRunLoop().addTimer(it, NSRunLoopCommonModes)
}
}
}
actual fun cancel() {
timer?.invalidate()
timer = null
}
actual fun isRunning(): Boolean {
return timer != null
}
}
The function you are trying to use is JVM only. See
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.concurrent/fixed-rate-timer.html
I'm looking for a way to pass an argument into a Kotlin sequence function similar to how it works in JS:
function *gen () {
console.log(yield) // prints 1
console.log(yield) // prints 2
}
const it = gen()
it.next() // first iteration will execute the first yield and pause
it.next(1) // we pass 1 to the first yield which will be printed
it.next(2) // we pass 2 to the second yield which will be printed
Something like this in Kotlin:
fun main() {
val it = gen().iterator()
// Iterator#next() doesn't expect an argument
it.next(1)
it.next(2)
}
fun gen() = sequence {
println(yield(null)) // Would print 1
println(yield(null)) // Would print 2
}
Kotlin Sequences do not support passing arguments to each yield, but you have at least 2 ways to implement needed behaviour:
Using actors:
class NextQuery<A, T>(val arg: A, val next: CompletableDeferred<T> = CompletableDeferred())
fun test() = runBlocking {
val actor = GlobalScope.actor<NextQuery<String, Int>> {
for (nextQuery in channel) {
nextQuery.next.complete(nextQuery.arg.length)
}
}
val query1 = NextQuery<String, Int>("12345")
actor.send(query1)
println(query1.next.await())
val query2 = NextQuery<String, Int>("1234")
actor.send(query2)
println(query2.next.await())
}
Using channels:
class ArgSequenceScope<out A, in T>(
private val argChannel: ReceiveChannel<A>,
private val nextChannel: SendChannel<T>
) {
suspend fun yield(next: T) {
nextChannel.send(next)
}
suspend fun arg(): A = argChannel.receive()
}
class ArgSequence<in A, out T>(
private val argChannel: SendChannel<A>,
private val nextChannel: ReceiveChannel<T>
) {
suspend fun next(arg: A): T {
argChannel.send(arg)
return nextChannel.receive()
}
}
fun <A, T> sequenceWithArg(block: suspend ArgSequenceScope<A, T>.() -> Unit): ArgSequence<A, T> {
val argChannel = Channel<A>()
val nextChannel = Channel<T>()
val argSequenceScope = ArgSequenceScope(argChannel, nextChannel)
GlobalScope.launch {
argSequenceScope.block()
argChannel.close()
nextChannel.close()
}
return ArgSequence(argChannel, nextChannel)
}
fun test() {
val sequence = sequenceWithArg<String, Int> {
yield(arg().length)
yield(arg().length)
}
runBlocking {
println(sequence.next("12345"))
println(sequence.next("1234"))
}
}
I am attempting to accept input from the console in Kotlin but it is difficult because I am not too sure about the syntax.
I begin with the main
fun main(args: Array<String>) {
}
WHAT should I enter after this? I am aware that the println() and readline() are involved but I do not know how to structure them.
Objective: prompt user to enter a number, the number entered is multiplied by 6, program returns the result to the console display.
Note that since Kotlin 1.6 readLine()!! should be replaced with
readln().
Here are A+B examples in Kotlin reading from stdin:
fun main() {
val (a, b) = readLine()!!.split(' ')
println(a.toInt() + b.toInt())
}
or
fun main(vararg args: String) {
val (a, b) = readLine()!!.split(' ').map(String::toInt)
println(a + b)
}
or
fun readInts() = readLine()!!.split(' ').map { it.toInt() }
fun main(vararg args: String) {
val (a, b) = readInts()
println(a + b)
}
or
import java.util.Scanner
fun main() {
val input = Scanner(System.`in`)
val a = input.nextInt()
val b = input.nextInt()
println(a + b)
}
or
with(Scanner(System.`in`)) {
val a = nextInt()
val b = nextInt()
println(a + b)
}
Competitive programming
Must-read intro: https://kotlinlang.org/docs/tutorials/competitive-programming.html
Must-watch Kotlin productivity videos: https://www.jetbrains.com/icpc/
Here is an (inspired by the article) extended bunch of helper functions for reading all possible types, lists, arrays, 2d-arrays, etc:
private fun readln() = readLine()!!
private fun readlnByte() = readln().toByte()
private fun readlnShort() = readln().toShort()
private fun readlnInt() = readln().toInt()
private fun readlnLong() = readln().toLong()
private fun readlnFloat() = readln().toFloat()
private fun readlnDouble() = readln().toDouble()
private fun readlnBigInt(radix: Int = 10) = readln().toBigInteger(radix)
private fun readlnBigDecimal() = readln().toBigDecimal()
private fun lineSequence(limit: Int = Int.MAX_VALUE) = generateSequence { readLine() }.constrainOnce().take(limit)
private fun readlnStrings() = readln().split(' ')
private fun readlnBytes() = readlnStrings().map { it.toByte() }
private fun readlnShorts() = readlnStrings().map { it.toShort() }
private fun readlnInts() = readlnStrings().map { it.toInt() }
private fun readlnLongs() = readlnStrings().map { it.toLong() }
private fun readlnFloats() = readlnStrings().map { it.toFloat() }
private fun readlnDoubles() = readlnStrings().map { it.toDouble() }
private fun readByteArray() = readlnStrings().run { ByteArray(size) { get(it).toByte() } }
private fun readShortArray() = readlnStrings().run { ShortArray(size) { get(it).toShort() } }
private fun readIntArray() = readlnStrings().run { IntArray(size) { get(it).toInt() } }
private fun readLongArray() = readlnStrings().run { LongArray(size) { get(it).toLong() } }
private fun readFloatArray() = readlnStrings().run { FloatArray(size) { get(it).toFloat() } }
private fun readDoubleArray() = readlnStrings().run { DoubleArray(size) { get(it).toDouble() } }
private fun readlnByteArray(n: Int) = ByteArray(n) { readlnByte() }
private fun readlnShortArray(n: Int) = ShortArray(n) { readlnShort() }
private fun readlnIntArray(n: Int) = IntArray(n) { readlnInt() }
private fun readlnLongArray(n: Int) = LongArray(n) { readlnLong() }
private fun readlnFloatArray(n: Int) = FloatArray(n) { readlnFloat() }
private fun readlnDoubleArray(n: Int) = DoubleArray(n) { readlnDouble() }
private fun readByteArray2d(rows: Int, cols: Int) = Array(rows) { readByteArray().also { require(it.size == cols) } }
private fun readShortArray2d(rows: Int, cols: Int) = Array(rows) { readShortArray().also { require(it.size == cols) } }
private fun readLongArray2d(rows: Int, cols: Int) = Array(rows) { readLongArray().also { require(it.size == cols) } }
private fun readIntArray2d(rows: Int, cols: Int) = Array(rows) { readIntArray().also { require(it.size == cols) } }
private fun readFloatArray2d(rows: Int, cols: Int) = Array(rows) { readFloatArray().also { require(it.size == cols) } }
private fun readDoubleArray2d(rows: Int, cols: Int) = Array(rows) { readDoubleArray().also { require(it.size == cols) } }
private fun isWhiteSpace(c: Char) = c in " \r\n\t"
// JVM-only targeting code follows next
// readString() via sequence is still slightly faster than Scanner
private fun readString() = generateSequence { System.`in`.read().toChar() }
.dropWhile { isWhiteSpace(it) }.takeWhile { !isWhiteSpace(it) }.joinToString("")
private fun readByte() = readString().toByte()
private fun readShort() = readString().toShort()
private fun readInt() = readString().toInt()
private fun readLong() = readString().toLong()
private fun readFloat() = readString().toFloat()
private fun readDouble() = readString().toDouble()
private fun readBigInt(radix: Int = 10) = readString().toBigInteger(radix)
private fun readBigDecimal() = readString().toBigDecimal()
private fun readBytes(n: Int) = generateSequence { readByte() }.take(n)
private fun readShorts(n: Int) = generateSequence { readShort() }.take(n)
private fun readInts(n: Int) = generateSequence { readInt() }.take(n)
private fun readLongs(n: Int) = generateSequence { readLong() }.take(n)
private fun readFloats(n: Int) = generateSequence { readFloat() }.take(n)
private fun readDoubles(n: Int) = generateSequence { readDouble() }.take(n)
Beware that Scanner is somewhat slow. This may be important in some cases like competitive programming where program's execution on large inputs could be made up to two times faster just by replacing Scanner with plain readLine. Even my suboptimal readString() implementation tokenizing via sequence is slightly faster. It allows to read input tokens until any next whitespace unlike Kotlin's built-in readLine().
I hope someday a concise, crossplatform, performant, universal for both console and files input parsing support would be introduced in Kotlin stdlib. Like readInt, readLong, etc global and Reader extension functions.
This would be very userful not only for competitive programming but also for learning Kotlin as first language.
A concept of reading a number shouldn't require first explaining collections, lambdas and monads.
Bonus
Sometimes you start with console input/output but then need to switch to files.
It becomes too tedious to prepend every read or write call with file stream variable.
Here is a peace of Kotlin magic that allows to just wrap unchanged console code with a couple of lines to force it read and write to files also ensuring they are closed properly:
fun <T : Closeable, R> T.useWith(block: T.() -> R): R = use { with(it, block) }
File("a.in").bufferedReader().useWith {
File("a.out").printWriter().useWith {
val (a, b) = readLine()!!.split(' ').map(String::toInt)
println(a + b)
}
}
Scanner(File("b.in")).useWith {
PrintWriter("b.out").useWith {
val a = nextInt()
val b = nextInt()
println(a + b)
}
}
Wrapping lines can be quickly commented out when happens a need to switch back to console.
Use readLine() to take input from user,
ATQ:
fun main(args:Array<String>){
print("Enter a number")
var variableName:Int = readLine()!!.toInt() // readLine() is used to accept the String value and ".toInt()" will convert the string to Int.
var result:Int= variableName*6
print("The output is:$result")
}
There are multiple alternatives to handle Console I/O with Kotlin.
1. Using the Kotlin Standard Library: The Kotlin standard library provides us extensions to handling I/O based on the classes of the JDK.
To print in the console we can use the print function. If we run the following snippet:
print("Hello from Kotlin")
We’ll see the following message displayed on our terminal:
Hello from Kotlin
Behind-the-scenes this function uses the Java System.out.print method. Also, the library offers us the println alternative function, witch adds the line separator at the end of the message.
In order to read from the console, we can use readLine function:
val inputText = readLine()
2. Using the Java Standard Library: Kotlin has great interoperability with Java. Thus, we can use the standard I/O classes from the JDK in our programs in case we need them.
2.1. Using the Scanner Class: Using the Scanner class is very straightforward; we only need to create an instance and use the nextLine method:
val scanner = Scanner(System.`in`)
val readText = scanner.nextLine()
Note that we are escaping the in property with backticks because it’s a keyword in Kotlin.
2.2. Using the BufferedReader Class: To use the BufferedReader class to read from the standard input stream, we first need to instantiate with System.in:
val reader = BufferedReader(InputStreamReader(System.`in`))
And then we can use its methods — for example, readLine():
val readText = reader.readLine()
2.3. Using the Console Class: Unlike the two previous classes, the Console class has additional methods for handling console I/O, like readPassword and printf.
In order to use the Console class we need to get the instance from the System class:
val console = System.console()
val readText = console.readLine()
Also, thanks to Kotlin’s interoperability with Java, we can use additional Java libraries for handling I/O.
In your case, after reading the input you can convert the String value to Int using the toInt() function.
fun readInts(separator: Char = ' ') =
readLine()!!.split(separator).map(String::toInt)
fun main(args: Array<String>) {
var A : List<Int> = readInts()
}
By default readLine takes input as string
toInt can be used to convert it to integer
fun main(args:Array<String>){
var first: Int
var second: Int
println("Enter the first number")
first = readLine()!!.toInt()
println("Enter the second number")
second= readLine()!!.toInt()
println("The sum is ${first + second}")
}
Below is the basic function to take the system input
fun main(args: Array<String>) {
val sc = Scanner(System.`in`)
val num1 = sc.nextInt()
val num2 = sc.nextInt()
val sum = solveMeFirst(num1, num2)
println(sum)
}
Just create a scan function
fun scan():String{
var str ="";
while ( str==""){
str = readLine().toString()
}
return str;
}
Use like
fun main() {
println("Enter number 1")
val a = scan().toInt()
println("Enter number 2")
val b = scan().toInt()
println(a + b);
}
You can use readLine().
fun main(args: Array<String>) {
println("What's your name?")
val inputText = readLine()
println(“Your name is " + inputText)
}