Hi everyone, I am DHL. ByteCode, focus on the latest technology to share original articles, involving Kotlin, Jetpack, algorithm animation, data structure, system source code, LeetCode/point Offer/multithreading/domestic and foreign large factory algorithm problems and so on.

  • Blog.autsoft. Hu /top-10-kotl…
  • Translator: DHL
  • This paper has been included in the warehouse Technical-Article-Translation

These are some of the most popular Kotlin questions on Stack Overflow. For a more in-depth analysis of each question, you can write a separate article. I will further analyze these questions later.

In this article you will learn the following:

  • Array<Int>IntArrayAnd how to choose
  • 可迭代SequenceAnd how to choose
  • There are eight common ways to traverse For loops
  • How do I use SAM transformations in Kotlin
  • How to declare a static member that Java and Koltin interoperate with
  • Why can’t kotlin’s smart transformations be used for mutable attributes, and how can this be fixed
  • When overriding a Java function, how do you determine the nullability of arguments
  • How do I use multiple extension functions and classes with the same name in one file

The translation

Difference between Array and IntArray

Array

Array

can store a fixed number of elements for any TYPE of T. It is used with arguments of type Int, such as Array

, and compiled into Java code generates instances of Integer[]. We can create arrays using the arrayOf method.

val arrayOfInts: Array<Int> = arrayOf(1, 2, 3, 4, 5)
Copy the code

IntArray

IntArray allows us to take arrays of primitive data types, compile them into Java code, and generate ints [] (other primitive arrays include ByteArray, CharArray, etc.). We can create arrays using the intArrayOf factory method.

val intArray: IntArray = intArrayOf(1, 2, 3, 4, 5)
Copy the code

When to useArray<Int>Or IntArray

IntArray is used by default because it performs better and does not require boxing every element. IntArray initializes the value of each index to 0 by default, as shown below.

val intArray = IntArray(10)
val arrayOfInts = Array<Int>(5) { i -> i * 2 }
Copy the code

If you need to create an Array containing null values, Kotlin also provides arrayOfNulls to help you do so.

val notActualPeople: Array<Person? > = arrayOfNulls<Person>(13)Copy the code

Difference between Iterable and Sequence

可迭代

Iterable corresponds to Java’s java.lang.Iterable, which immediately processes the input elements and returns a new collection containing the results. Let’s take a simple example and return the set of the first five people whose age > 21.

val people: List<Person> = getPeople()
val allowedEntrance = people
		.filter { it.age >= 21 }
		.map { it.name }
		.take(5)
Copy the code
  • First of all byfilterThe function checks each person’s age and puts the results into a new result set
  • throughmapThe function names the results of the previous step and generates a new listlist<String>
  • throughtakeThe function returns the first five elements for the final result set

Sequence

Sequence is a new concept in Kotlin to represent a set of delayed computations. Sequence stores only operations and does not process any elements until the terminal operator is encountered. We can also use the asSequence extension function to convert an existing collection into a Sequence, as shown below.

val people: List<Person> = getPeople()
val allowedEntrance = people.asSequence()
	.filter { it.age >= 21 }
	.map { it.name }
	.take(5)
	.toList()
Copy the code

In this example, toList() represents the terminal operator. Filter, map, and take are all intermediate operators that return Sequence instances. When Sequence encounters the intermediate operator, it only stores the operation process and does not participate in the calculation until toList() is encountered.

Benefits of Sequence It does not generate an intermediate result set, and simply repeats this step for each person in the original list until five people are found and the final result set is returned.

How to choose

If the amount of data is small, use Iterable. Although an intermediate result set is created, the performance impact is not significant in the case of small data.

If you are dealing with a large amount of data, Sequence is the best choice because no intermediate result set is created and the memory overhead is lower.

There are eight common ways to traverse a For loop

We often traverse using the following methods.

for (i in 0.. args.size - 1) { println(args[i]) }Copy the code

But Array has a more readable extension called lastIndex.

for (i in 0.. args.lastIndex) { println(args[i]) }Copy the code

But actually we don’t need to know the last index, there’s a simpler way to write it.

for (i in 0 until args.size) {
	println(args[i])
}
Copy the code

Of course you can use subscript extended property indices to get the scope.

for (i in args.indices) {
	println(args[i])
}
Copy the code

A more direct way to write this is to iterate over the collection directly as follows.

for (arg in args) {
	println(arg)
}
Copy the code

You can also use the forEach function to pass a lambda expression to handle each element.

args.forEach { arg ->
	println(arg)
}
Copy the code

The Generated Java code is very similar; in each case, an index variable is added and elements are retrieved through the index in a loop. But if we iterate over a List, the last two examples use iterators at the bottom, while the others still get elements by index. There are two other ways to traverse:

  • withIndexFunction, which returns a可迭代Object that can be deconstructed into the current index and element.
for ((index, arg) in args.withIndex()) {
    println("$index: $arg")
}
Copy the code
  • forEachIndexedFunction, which provides a lambda expression for each index and parameter.
args.forEachIndexed { index, arg ->
    println("$index: $arg")
}
Copy the code

How do I use SAM transformations

SAM transformations can be implemented using lambda expressions to make code cleaner and more readable. Let’s look at an example.

Define an OnClickListener interface in Java and declare an onClick method.

public interface OnClickListener {
    void onClick(Button button);
}
Copy the code

We add an OnClickListener to the Button that will be called every time it is clicked.

public class Button { public void setListener(OnClickListener listener) { ... }}Copy the code

Common in Kotlin, create an anonymous class that implements the OnClickListener interface.

button.setListener(object: OnClickListener { override fun onClick(button: Button) { println("Clicked!" )}})Copy the code

If we use SAM transformations, the code will be much cleaner and more readable.

button.setListener { fun onClick(button: Button) { println("Clicked!" )}}Copy the code

How to declare a static member that Java and Koltin interoperate with

A normal class can have both static and non-static members, and in Kotlin we often put static members in companion Objects.

class Foo { companion object { fun x() { ... } } fun y() { ... }}Copy the code

We can also declare a singleton with Object instead of companion Object.

object Foo { fun x() { ... }}Copy the code

If you don’t always want to call foo.x () by class name and just want to use x(), you can declare it as a top-level function.

fun x() { ... }
Copy the code

In addition, to call Kotlin static methods in Java, you need to add @jVMStatic and @jVMName annotations. Here’s a table summarizing how to call the code in Kotlin in Java.

Function declaration Kotlin usage Java usage
Companion object Foo. F () Foo. Companion. F ();
Companion object with @JvmStatic Foo. F () Foo. F ();
Object Foo. F () Foo. INSTANCE. F ();
Object with @JvmStatic Foo. F () Foo. F ();
Top level function f () UtilKt. F ();
Top level function with @JvmName f () Util. F ();

The same rule applies to variables, where the @jVMField annotation is used, along with the const keyword, to inline constant values at compile time into the call.

Variable declaration Kotlin usage Java usage
Companion object X. X X. Companion. GetX ();
Companion object with @JvmStatic X. X X. GetX ();
Companion object with @JvmField X. X X. X;
Companion object with const X. X X. X;
Object X. X X. INSTANCE. GetX ();
Object with @JvmStatic X. X X. GetX ();
Object with @JvmField X. X X. X
Object with const X. X X. X;
Top level variable X. X ConstKt. GetX ();
Top level variable with @JvmField X. X ConstKt. X;
Top level variable with const x ConstKt. X;
Top level variable with @JvmName x Const. GetX ();
Top level variable with @JvmName and @JvmField x Const. X;
Top level variable with @JvmName and const x Const. X;

Why can’t smart transformations in Kotlin be used for mutable attributes

Let’s start with a piece of problematic code.

class Dog(var toy: Toy? = null) { fun play() { if (toy ! = null) { toy.chew() } } }Copy the code

The above code failed at compile time with the exception information shown below.

Kotlin: Smart cast to 'Toy' is impossible, because 'toy' is a mutable property that could have been changed by this time
Copy the code

The reason for this problem is that after executing toy! Between = null and the toy.chew() method being called, the Dog instance may be modified by another thread, which may result in a NullPointerException.

How can we solve this problem

All variables are declared with val by default, except when necessary, when they are set to var.

If you must declare var, you can solve this problem by using a locally immutable copy. Modify the above code as shown below.

class Dog(var toy: Toy? = null) { fun play() { val _toy = toy if (_toy ! = null) { _toy.chew() } } }Copy the code

But there’s a simpler way to write it.

class Dog(var toy: Toy? = null) { fun play() { toy? .length } }Copy the code

When overriding a Java function, how do you determine the nullability of arguments

Define an OnClickListener interface in Java and declare an onClick method.

public interface OnClickListener {
    void onClick(Button button);
}
Copy the code

Implementing this interface in Kotlin and automatically generating the onClick method through IDEA will result in the following method signature. The onClick method parameter is nullable by default.

class KtListener: OnClickListener { override fun onClick(button: Button?) : Unit { val name = button? .name ?: "Unknown button" println("Clicked $name") } }Copy the code

Since the Java platform does not have nullable types, and Kotlin does, it is up to us to decide whether Button is null in this example. By default, it is safer to use nullable types for all arguments, which the compiler forces us to handle.

For parameters that are known to never be empty, non-empty types can be used. Both null and non-null will compile normally, but if you declare method arguments as non-empty, the Kotlin compiler will automatically inject an empty check, possibly throwing IllegalArgumentException, and potentially very risky. Of course, using non-null parameters makes the code much cleaner.

class KtListener: OnClickListener {
    override fun onClick(button: Button): Unit {
        val name = button.name
        println("Clicked $name")
    }
}
Copy the code

How do I use multiple extension functions and classes with the same name in one file

Suppose you implement two extension functions with the same name on the String class in different packages. If it’s a normal function, you can call it with the fully qualified package name, but extension functions don’t. So we can rename it using the AS keyword in the import statement, as shown below.

import com.example.code.indent as indent4
import com.example.square.indent as indent2

"hello world".indent4()
Copy the code

In another case, you want to use two classes with the same name from different packages in the same file (for example, java.util.date and java.sql.date), and you don’t want to invoke them by fully qualifying the package name. We can also rename it using the AS keyword in the import statement.

import java.util.Date as UtilDate
import java.sql.Date as SqlDate
Copy the code

We can now refer to these classes in this class using aliases declared by the AS keyword.

The translator

This is the end of the full text, each question in this article is a knowledge point, and I will write a separate article for each question later for a more in-depth analysis.

A “like” would be the biggest encouragement if it helps

Welcome to the public account: ByteCode, continue to share the latest technology


Finally, recommend long-term update and maintenance projects:

  • Personal blog, will all articles classification, welcome to check hi-dhl.com

  • KtKit compact and practical, written in Kotlin language tool library, welcome to check KtKit

  • Androidx-jetpack-practice androidX-Jetpack-practice androidX-Jetpack-practice androidX-Jetpack-Practice androidX-Jetpack-Practice

  • LeetCode/multiple thread solution, language Java and Kotlin, including a variety of solutions, problem solving ideas, time complexity, spatial complexity analysis

  • Job interview with major companies at home and abroad
  • LeetCode: Read online

Must-read articles these days

  • Value class completely replaces TypeAlias?
  • A few Kotlin details that are easy to overlook, value class execution is surprisingly efficient
  • Kotlin announced a blockbuster feature
  • Launching a website in 1 minute – no domain name, no server – has never been easier
  • Box-sizing: border-box! Important; word-wrap: break-word! Important; “> < span style =” max-width: 100%
  • Android 12 is here, did your App crash?
  • Google has announced the abandonment of the LiveData.observe method
  • One detail to note when using Kotlin
  • Kotlin code affecting Performance (1)
  • Jetpack Splashscreen parsing | power generation IT migrant workers get twice the result with half the effort
  • Kotlin’s Technique and Analysis (3)
  • Uncover the == and === in Kotlin
  • The Kotlin hermetic class evolved