In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-03 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
Today I will show you how to avoid the traps in Kotlin. The content of the article is good. Now I would like to share it with you. Friends who feel in need can understand it. I hope it will be helpful to you. Let's read it along with the editor's ideas.
Kotlin is very popular these days, and I agree that Kotlin is a well-thought-out language, except for the shortcomings mentioned below. Here are some of the pitfalls I encountered in the development process, and teach you how to avoid them.
Enigmatic null
In Kotlin, you don't have to think about how to deal with null in your code, which makes you forget that null is ubiquitous, but hidden. Take a look at the following class that looks fine on the surface:
Class Foo {privateval c: String init {bar () c = ""} private fun bar () {println (c.length)}}
If you try to initialize this class, the code will throw a NullPointerException. Because the bar method tries to access the c variable before it is initialized.
Although the code itself is problematic, it causes the exception to be thrown. But what's worse is that your compiler won't find it.
Kotlin can help you avoid null in most cases, but you can't forget the existence of null. Or sooner or later you will run into a similar problem.
Null from JDK
Kotlin's standard library can handle null very well. But if you use classes in JDK, you need to handle the null pointers that may be generated by JDK method calls.
In most cases, Kotlin's standard library is sufficient, but sometimes you need to use ConcurrentHashMap:
Val map = ConcurrentHashMap () map ["foo"] = "bar" val bar: String = map ["foo"]!!
At this point, you need to use! Operator. But in some cases you can also use things like (?) Replace it with such an operator that is safe for null. Still, when you use it! Or when you write an adapter to use the Java class library, you will find that the code is messed up because of these changes. This is a problem that you can't avoid.
You may encounter more and more terrible problems. When you use a method in the JDK class, the return value may be null, and there is no syntax sugar like Map access.
Consider the following examples:
Val queue: Queue = LinkedList () queue.peek (. ToInt ()
In this case, you use the peek method that may return a null value. But the Kotlin compiler will not prompt you for this problem, so a NullPointerException exception may be triggered when your Queue is an empty queue.
The problem is that the Queue we use is an interface to JDK, and when you look at the documentation for the peek method:
/ * Retrieves, but does not remove, the head of this queue, * or returns {@ code null} if this queue is empty. * * @ return the head of this queue, or {@ code null} if this queue is empty * / E peek ()
The document says that the peek method returns an object of type E, but Kotlin believes that E is not nullable. This may be solved in the next version of Kotlin, but now when you use similar interfaces in your project, be sure to pay attention to:
Val queue: Queue = LinkedList () queue.peek ()? .toInt ()
Internal it
When a lambda expression has only one parameter, you can omit it in your code and use it instead.
It: the internal name of the single parameter. This is a useful feature when your expression has only one parameter, the declaration process can be omitted (like->), and the parameter name is it.
The problem is that when you have a nested function in your code like the following example:
Val list = listOf ("foo.bar", "baz.qux") list.forEach {it.split (".") .forEach {println (it)}}
The it parameter can be confused. The solution is a declaration shown like this:
List.forEach {item-> item.split ("."). ForEach {part-> println (part)}}
Doesn't it look much better!
Hidden replication
Notice the following classes:
Data class Foo (val bars: MutableList)
The data class provides a series of methods, and you can mirror them by copying them. Guess what the following code will output?
Val bars = mutableListOf ("foobar", "wombar") val foo0 = Foo (bars) val foo1 = foo0.copy () bars.add ("oops") println (foo1.bars.joinToString ())
The console will output foobar, wombar, oops. The problem is that the copy method does not actually copy a complete object, but rather copies a reference to the object. This problem can occur when you forget to write a unit test class and pass your data class as immutable.
The solution is to be careful when you use the data class, and when you have to use it as a value object, like this:
Data class Foo (val bars: List)
The data class has another problem: the properties used by its equals / hashCode methods are immutable. You can only modify the return value by overriding these methods manually. Keep this in mind.
Internal method exposure
Consider the following example carefully:
Class MyApi {fun operation0 () {} internal fun hiddenOperation () {}}
The internal keyword takes effect when you reference this class in a Kotlin project. But when you use it from a Java project, hiddenOperation becomes a public method! To avoid this, I recommend using interfaces to hide the details of the implementation:
Interface MyApi {fun operation0 ()} class MyApiImpl: MyApi {override fun operation0 () {} internal fun hiddenOperation () {}}
Special global extension
There is no doubt that the function of the extension function is very important. But usually, the greater the ability, the greater the responsibility. For example, you can write global JDK class extension functions. But it can cause a lot of trouble when this function is only meaningful in the local context and is globally visible.
Fun String.extractCustomerName (): String {/ /...}
Everyone who jumps to your method will be at a loss. So I think you should think twice before you write such a method. Here is a suggestion:
/ * * Returns an element of this [List] wrapped in an Optional * which is empty if `idx` is out of bounds. * / fun List.getIfPresent (idx: Int) = if (idx > = size) {Optional.empty ()} else {Optional.of (get (idx))} / * * Negates `isPresent`. * / fun Optional.isNotPresent () = isPresent.not ()
Lambdas Unit return value vs Java SAM conversion
If your function argument is a lambdas expression and the return type is Unit, you can omit the return keyword:
Fun consumeText (text: String, fn: (String)-> Unit) {} / / usage consumeText ("foo") {println (it)}
This is an interesting feature, but it can be awkward when you call this method in Java code:
ConsumeText ("foo", (text)-> {System.out.println (text); return Unit.INSTANCE;})
This is not friendly to the Java side. If you want to successfully call the method in Java, you need to define the following API:
Nterface StringConsumer {fun consume (text: String)} fun consumeText (text: String, fn: StringConsumer) {}
Then you can use Java's SAM transformation.
ConsumeText ("foo", System.out::println)
But on the Kotlin side, it looks bad:
ConsumeText ("foo", object: StringConsumer {override fun consume (text: String) {println (text)}})
The crux of the problem is that only Java supports SAM transformations, not Kotlin. My suggestion is to simply use Java's SAM interface as a consumer in a simple scenario:
Fun consumeText (text: String, fn: Consumer) {} / / usage from Kotlin consumeText (foo, Consumer {println (it)}) / / usage from Java consumeText ("foo", System.out::println)
Using immutable sets in Java
Kotlin provides an immutable version of the JDK collection class.
Fun createSet (): Set = setOf ("foo") / /. CreateSet () .add ("bar") / / oops, compile error
This is a good supplement. But when you look at Java JDK's Set class API, you will find:
CreateSet () .add ("bar") / / UnsupportedOperationException
When you try to modify the Set, the exception is thrown, just as you used the Collections.unmodifiableSet () method. I don't know if this makes sense, but you need to keep this in mind when using the immutable version of the Java collection class of Kotlin.
There is no overload in the interface
Kotlin does not support the use of @ JvmOverloads annotations on interfaces, and neither can override.
Interface Foo {@ JvmOverloads / / OUCH! Fun bar (qux: String)} class FooImpl: Foo {@ JvmOverloads / / YIKES! Override fun bar (qux: String) {}}
You can only define it manually as follows:
Interface Foo {fun bar () fun bar (qux: String)}
Keep in mind that you can use KEEP (Kotlin Evolution and Enhancement Process) in Kotlin to improve. KEEP is similar to JEP in Java, but much more concise than JEP.
Kotlin is very popular right now, and I think it's an enhanced version of Java. But you still need to stay awake when using Kotlin, especially if you are in the midst of all kinds of publicity about Kotlin. If you want to use Kotlin, be sure to pay attention to the Kotlin-related defects we mentioned above.
This is all about how to avoid the traps in Kotlin. For more content related to how to avoid traps in Kotlin, you can search the previous articles or browse the following articles to learn! I believe the editor will add more knowledge to you. I hope you can support it!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.