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.

This is the third article on value class. I have already written two articles to analyze value class from different perspectives.

  • Value class is a very useful feature that can improve code readability and performance, as described in Kotlin 1.5’s Value Class article, which examines value class and inline class in detail.

  • In this article, we analyze the performance of value classes and data classes in detail, as well as the details that need to be paid attention to when using value classes

This article will analyze value classes from the perspectives of type safety, memory footprint, execution efficiency, and usage scenarios. Through this article, you will learn the following.

  • What is thevalue class
  • What is thetypealias
  • typealiasType safety cannot be guaranteed
  • typealiasvalue classNo additional objects will be created
  • value classtypealiasExecution efficiency of
    • typealiasCompare with the original String type
    • value classtypealiascontrast
  • value classtypealiasAdvantages and usage scenarios

What is a value class

The value class represents an inline class that requires passing in a parameter to the main constructor and is decorated with val. When compiled into Java code, it is replaced with the value passed in, as shown below.

@JvmInline
value class User(val name: String)

fun login(user: User?): String = user? .name ?:""

fun testInline(a) {
    println(login(User("DHL")))}// The compiled code
public static final String login_js0Jwf8/* $FF was: login-js0Jwf8*/(@Nullable String user) {
    / /...
  return var10000;
}

public static final void testInline(a) {
    String var0 = login-js0Jwf8("DHL");
    System.out.println(var0);
}
Copy the code

As you can see, the compiled Java code does not create additional objects, but instead replaces the object User created in Kotlin with the value DHL passed in.

What is typealias

In Kotlin’s source code, expressions that encounter long signatures more or less use TypeAlias, which simply gives the class an alias.

typealias Password = String
fun inputPassword(password: Password){}fun main(a) {
    val password: Password = "123456"
    inputPassword(password)
}
Copy the code

Using the TypeAlias keyword, alias Password is given to the String type, and you can then use Password as if it were String.

A value class is a data class and a value class is a data class. A value class is a data class. Whether a value class can completely replace a TypeAlias.

Typealias does not guarantee type safety

A String can represent many things, such as a user name, password, and so on. We can also alias the user name and password with the TypeAlias keyword.

typealias Username = String
Copy the code

InputPassword (password: String) is of type String, so we can pass in typeAlias alias Username because the type is the same and assignment is compatible, as shown below.

fun inputPassword(password: String){}val userName: Username = "ByteCode"
inputPassword(userName)
Copy the code

Although this is a password-input function, if the caller passes in a username, assignment is compatible because the type is the same, this is not detected at compile time, but can have unpredictable consequences at run time.

The emergence of value class helps us solve this problem. We can also use data class or other classes to solve this problem, but there will be additional performance overhead. For a closer look at a few Kotlin details that were easily overlooked in previous articles, value class execution is surprisingly efficient.

@JvmInline
value class Password(val value: String) { }

fun inputPassword(password: Password){}Copy the code

Now if we pass in an unwanted parameter to the inputPassword() function, it will be checked at compile time.

Typealias, like Value Class, does not create additional objects

A Value Class does not create additional objects from a memory point of view, as does typeAlias, which is compiled as shown below.

typealias Password = String
fun inputPassword(password: Password){}// The compiled code
public static final void inputPassword(@NotNull String password) {
  / /...
}
Copy the code

The compiled code for value Class looks like this.

@JvmInline
value class Password(val value: String) { }
fun inputPassword(password: Password){} Compiled codepublic static final void inputPassword_ZVkiumU(@NotNull String password) {
    / /...
}
Copy the code

As you can see, there is no additional object creation overhead for either value Class or TypeAlias.

Value Class and TypeAlias execution efficiency

Let’s look at value Class and TypeAlias execution efficiency from the following perspectives.

  • typealiasCompare with the original String type
  • value classtypealiascontrast
  • value classdata classContrast, contrast, contrast, contrastThe articleIt has been analyzed and ignored here)

Typealias compared to the original String type

Using the typeAlias keyword to alias String Password, we use an example to verify the efficiency of the Password and the primitive String.

fun inputPassword(password: String){}fun inputPasswordTypealias(password: Password){}typealias Password = String
@ExperimentalTime
fun main(a) {

    // Primitive type
    val measureString = measureTime {
        repeat(1000) {
            inputPassword("123456")
        }
    }
    println("measure string time  ${measureString.toDouble(TimeUnit.MILLISECONDS)} ms")

    // typealias
    val measuretypealias = measureTime {
        repeat(1000) {
            inputPasswordTypealias("123456")
        }
    }
    println("measure typealias time  ${measuretypealias.toDouble(TimeUnit.MILLISECONDS)} ms")}Copy the code

We tested String and TypeAlias respectively, and their results are shown below.

measure string time  5.475575 ms
measure typealias time  5.853019 ms
Copy the code

The result is essentially the same because the compiled Java code replaces the typeAlias declaration alias with the original type String.

Value Class compares with TypeAlias

Let’s take a look at the efficiency of value Class and TypeAlias. The code is simple as follows.

// typealias
typealias Password = String
fun inputPassword(password: Password) {}

// value class
@JvmInline
value class Password(val value: String) {}
fun inputPasswordValueClass(password: Password) {}

@ExperimentalTime
fun main(a) {

    // typealias
    val measureString = measureTime {
        repeat(1000) {
            inputPassword("123456")
        }
    }
    println("measure typealias time  ${measureString.toDouble(TimeUnit.MILLISECONDS)} ms")

    // value class
    val measureValueClass = measureTime {
        repeat(1000) {
            inputPasswordValueClass(Password("123456"))
        }
    }
    println("measure value class time  ${measureValueClass.toDouble(TimeUnit.MILLISECONDS)} ms")}Copy the code

The test results for value Class and TypeAlias are shown below.

measure typealias time    6.437296 ms 
measure value class time  6.66023 ms
Copy the code

As you can see, there is almost no difference between a Value class and a TypeAlias in terms of memory and performance. Is it possible to use a Value class instead of a TypeAlias entirely? This is shown to be impossible, and while value classes are efficient and powerful, they are used in completely different scenarios.

The advantages and usage scenarios of Value Class and TypeAlias

Based on the previous content and the analysis of value classes in the previous two articles, value classes have the following advantages:

  • Type safety prevents callers from doing things we don’t expect
  • It takes up less memory and is more efficient
  • Improved code readability
  • value classIs a real type that is more powerful and can have constructors, initializers, and other functions (getXXX()setXXX()) and so on, so that we can encapsulate the business logic

The biggest advantage of Data class compared with value class is that it supports multiple parameters, while value class only supports one parameter declared with Val. However, value class has much higher memory and execution efficiency than data class. When there’s a lot of data, the gap gets bigger and bigger.

measure data class time  6.790241 ms
measure value class time 0.832866 ms
Copy the code

Value class has so many advantages, but what about its usage scenarios? In fact, there is no fixed usage scenario, we can use value class in Toast, conversion between units (time, distance), location, Json serialization and deserialization, etc. After we understand their advantages and disadvantages, we can consider from more dimensions such as memory and execution efficiency.

Value classes have many advantages, but in some cases TypeAliases are better than value classes. When we use higher-order functions, Lambda expressions, expressions with long signatures, typeAliases are better. An example code is shown below.

inline fun  requestData(type: Int, call: (code: Int.type: Int) - >Unit) {
    call(200, type)
}
Copy the code

There is a Lambda expression in the method argument, and it is possible to change the parameters in the Lambda expression at any time in the future. If the Lambda expression is given an alias through typeAlias, the alias will not only improve the readability, but also facilitate uniform modification in the future. The final code is shown below.

typealias Callback = (code: Int, type: Int) - >Unit

inline fun  requestData(type: Int, call: Callback) {
    call(200, type)
}
Copy the code

So when we use higher-order functions and long-signed expressions, we can consider using TypeAlias.


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

More code, more articles

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

  • A few Kotlin details that are easy to overlook, value class execution is surprisingly efficient
  • 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?
  • Kotlin announced a blockbuster feature
  • 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