One of the biggest headaches a programmer has is not being able to read other people’s code. There are various reasons for this, but they boil down to complexity. Kotlin has gone to great lengths to reduce code complexity, using a series of new syntactic features to reduce syntax noise in order to express semantics more simply and bluntly.
This post shares my first impressions of Kotlin from the perspective of a programmer who just switched from Java to Kotlin.
new A semicolon type
New objects do not need the new keyword.
The end of any statement is not required; But it doesn’t make any grammar mistakes.
//java
StringBuffer buffer = new StringBuffer();
//kotlin
var buffer = StringBuffer()
Copy the code
var
iskotlin
Reserved word used to declare variables. And that corresponds toval
Used to declare a constant. A constant means that the reference is immutable, but does not mean that the object it references is immutable.- There is no need to display the specified variable type because
kotlin
The ability to infer variable types from context is calledType derivation 。 - The type can be specified using the following syntax:
var buffer: StringBuffer = StringBuffer()
Copy the code
kotlin
The type is postset, following the variable nameType:
You can display the specified type. Similarly, it is used to specify the return value type of a function:
fun getMessage(a): String{
return "message"
}
Copy the code
fun
The keyword is used to declare functions.
implements extends @Override
//java
public class CheckableActivity extends Activity {
final public void setStatus(){}
}
public class MyListener implements View.OnClickListener{
@Override
public void onClick(View v) {
}
}
//kotlin
class CirclePartyListActivity : Activity() {
fun setStatus(a){}}class MyListener : View.OnClickListener{
override fun onClick(v: View?).{}}Copy the code
-
Kotlin uses: instead of implements and extends.
-
Override is also replaced by the Override reserved word and goes with the function header. Override is required in Kotlin, but optional in Java.
-
Classes and methods in Kotlin are final by default (omitted), which means that by default, classes and methods are not allowed to be inherited or overridden (this is to prevent fragile base classes, where changes to base class methods cause subclasses to behave in ways that are not expected). Only by displaying the open reserved word declares that the class or method can be inherited or overridden:
open class A{
open fun do(a){}}Copy the code
(a)
Kotlin’s lambda is also more minimalist:
// Normal
view.setOnClickListener({ v -> v.setVisibility(View.INVISIBLE) })
// When lambda is the last argument to a function, it can be moved outside the parentheses
view.setOnClickListener() { v -> v.setVisibility(View.INVISIBLE) }
// When a function has only one argument of type lambda, you can leave out the parentheses
view.setOnClickListener { v -> v.setVisibility(View.INVISIBLE) }
// When lambda has only one argument, you can omit the argument list and refer to the argument with it in the expression section
view.setOnClickListener { it.setVisibility(View.INVISIBLE) }
Copy the code
getter setter
In Java, the combination of a field and its accessor is called a property. Kotlin introduced Property Access Syntax, which replaces the field and accessor methods, and simplifies the code further:
view.setOnClickListener { it.visibility = View.INVISIBLE }
Copy the code
- Everything is defined
getter
andsetter
Method field, inkotlin
Can be manipulated by assignment syntax.
{} return
The only difference between a statement and an expression in Kotlin is that an expression has a value and a statement does not. If the body of the function consists of a single expression, you can dispense with curly braces and return and assign the value of the expression to the return value with the = expression. This syntax is called the expression body:
//java
public int add(int a, int b){
return a+b ;
}
//kotlin
fun add(a: Int, b: Int): Int = a+b
Copy the code
When a lambda expression contains multiple statements or expressions, if return is omitted, the value of the last expression is returned by default:
view.setOnTouchListener { v, event ->
...//do something
false
}
Copy the code
This code means that false is returned in onTouchListener.ontouch ().
switch-case-break
//java
String color;
switch(colorInt){
case Color.RED:
color = "red";
break;
case Color.BLUE:
color = "blue";
break;
default:
color = "black";
break;
}
//kotlin
val color = when (colorInt) {
Color.RED -> "red"
Color.BLUE -> "blue"
else -> "black"
}
Copy the code
when
Used to replaceswitch-case
Do not need to be called at the end of each branchbreak
If a branch hits, it returns immediately.when
Is an expression, which means it has a return value equal to the value returned by the last statement in the hit branch.
default
The reserved word default in Java is used to implement the default method in an interface. You can leave it out in kotlin.
//java
public interface IMessage {
default String getMessage() {
return "default message";
}
int getMessageId();
}
//kotlin
interface IMessage {
fun getMessage(a): String {
return "default message"
}
fun getMessageId(a): Int
}
Copy the code
Int
isjava
The basic data type inint
Wrapper class,kotlin
There are no basic data types in
Defensive programming
//java
public class Address {
private String country;
public String getCountry() {
returncountry; }}public class Company {
private Address address;
public Address getAddress() {
returnaddress; }}public class Person {
private Company company;
public String getCountry() {
String country = null;
// Multiple defensive programming
if(company ! =null) {
if(company.getAddress() ! =null) { country = company.getAddress().getCountry(); }}returncountry; }}//kotlin
fun Person.getCountry(a): String? {
return this.company?.address?.country
}
Copy the code
? .
Referred to asSecure call operator, which combines a null-check and a method call into one operation. Only if the calling variable is notnull
Otherwise the entire expression is returnednull
. This means that defensive programming is no longer necessary.?
Placing after a type indicates that the type is nullable, and the above function declaration indicates that the return value of this function may benull
.- The kotlin code above is
Person
Class has been addedgetCountry()
Method, this technique is calledExtension function 。
Extension function
An extension function is a member function of a class, but it is defined outside the class body. The benefit of this definition is that you can add functionality to a class anytime, anywhere.
In an extension function, you can access the properties and methods of the class just like any other member function of the class (except for members that are private and protected). We can also use this to refer to an instance of the class, or we can omit it to further simplify the above code:
fun Person.getCountry(a): String? {
returncompany? .address? .country }Copy the code
Kotlin has ordered a number of extension functions, and the apply function is used:
Redundant object names
In programming, we often encounter “multiple operations on the same object” scenarios, such as:
Intent intent = new Intent(this, Activity1.class);
intent.setAction("actionA");
Bundle bundle = new Bundle();
bundle.putString("content"."hello");
bundle.putString("sender"."taylor");
intent.putExtras(bundle);
startActivity(intent);
Copy the code
Among them, intent and bundle are repeated several times, which is intolerable for minimalist Kotlin, and its expression is as follows:
Intent(this,Activity1::class.java).apply {
action = "actionA"
putExtras(Bundle().apply {
putString("content"."hello")
putString("sender"."taylor")
})
startActivity(this)}Copy the code
Where, apply is defined as follows:
// Add a new function apply() to the generic T object, which takes a lambda argument block, and the originator of the lambda call is the object itself
public inline fun <T> T.apply(block: T. () - >Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
//执行lambda
block()
// Return the caller itself
return this
}
Copy the code
Object. Apply {lambda} can be simply interpreted as applying a lambda operation on an object and returning the object itself. So the above code can also be written in a more compact form:
startActivity(Intent(this, Activity1::class.java).apply {
action = "actionA"
putExtras(Bundle().apply {
putString("content"."hello")
putString("sender"."taylor")})})Copy the code
Predefined extension functions of the same type include with, let, and ALSO. What they have in common is that they are applicable to the “multiple operations on the same object” scenario. Their differences are summarized as follows:
function | The return value | Caller role | How do I reference the caller |
---|---|---|---|
also | The caller itself | As a lambda parameter | it |
apply | The caller itself | As a lambda receiver | this |
let | Lambda return value | As a lambda parameter | it |
with | Lambda return value | As a lambda receiver | this |
kotlin
The object that initiates the call to the extension function is calledReceiver object. Similarly, the object that initiates the call to a lambda is calledLambda receiver.- Can be
also
The source andapply
To better understand the difference in their caller roles:
// Add a new function to the generic T object, also(), which takes a lambda parameter block, and the object is a lambda parameter
public inline fun <T> T.also(block: (T) - >Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block(this)
return this
}
Copy the code
Integrated application of
“Make all clicked views in the app have a zoom animation.” Before using the kotlin knowledge above to implement this requirement, let’s take a look at how Java does it:
- First define the utility class, which is passed in
View
Set the touch and click listeners separately. Play the animation when you press it down and reverse when you let it go.
public class ViewUtil {
public static void addExtraAnimClickListener(View view, ValueAnimator animator, View.OnClickListener listener) {
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
animator.start();
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
animator.reverse();
break;
}
// If true is returned, the click event is masked
return false; }}); view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(listener ! =null) { listener.onClick(v); }}}); }}Copy the code
- Create new animations and click response logic in the interface and pass them to the utility class
Button btn3 = findViewById(R.id.btn3);
// New animation: Make it bigger
ValueAnimator animator = ValueAnimator.ofFloat(1.0 f.1.2 f);
animator.setDuration(100);
animator.setInterpolator(new AccelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) { Float value = ((Float) animation.getAnimatedValue()); btn3.setScaleX(value); btn3.setScaleY(value); }});// Click the response logic
View.OnClickListener onClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(Activity1.this."spring anim", Toast.LENGTH_LONG).show(); }};// The application tool class
ViewUtil.addExtraAnimClickListener(btn3, animator, onClickListener);
Copy the code
Don’t blink, replace kotlin:
- Add extension functions to the View
// The extension function receives an animation and a click-response logic (lambda)
fun View.extraAnimClickListener(animator: ValueAnimator, action: (View) - >Unit) {
setOnTouchListener { v, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> animator.start()
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> animator.reverse()
}
false
}
setOnClickListener { action(this)}}Copy the code
- Application extension function
btnSpringAnim.extraAnimClickListener(ValueAnimator.ofFloat(1.0 f.1.15 f).apply {
interpolator = AccelerateInterpolator()
duration = 100
addUpdateListener {
btnSpringAnim.scaleX = it.animatedValue as Float
btnSpringAnim.scaleY = it.animatedValue as Float
}
}) { Toast.makeText(this."spring anim", Toast.LENGTH_LONG).show() }
Copy the code
btnSpringAnim
Is aButton
Control id (you don’t need findViewById() as long as the Kotlin plug-in is installed)as
Reserved words are used for type casting.- Is there a kind of“Vernacular to Classical Chinese”Feeling,
kotlin
With strong expressive power, it completed the function with nearly 1/3 of the code volume.
Summary of knowledge points
var
Reserved words are used to declare variables,val
Reserved words are used to declare constants. In most cases, there is no need to specify the type of the variable. Kotlin has the ability to deduce the type automatically based on the context.fun
Reserved words are used to declare functions.override
Reserved words denote overridden superclass methods or abstract methods in implementing interfaces, which, unlike Java, must appear before the overridden method (Java allows omission).as
Reserved words are used for type casting.- In Kotlin, the type is postset, followed by the variable name or function argument list
Type:
You can display the specified type. :
Also used for inherited classes (replaceextends
), implement the interface (replaceimplements
).- This is not required when creating new objects
new
Instead, call the constructor directly. - The end of the statement is not required
;
But it doesn’t make any grammar mistakes. - Classes and methods in Kotlin default to
final
They cannot be inherited and rewritten. Only by addingopen
Before it can be inherited and rewritten. - There are no basic data types in Kotlin, but instead are represented by their corresponding wrapper classes.
- This is not required when adding a default implementation to an interface method
default
The keyword. - The only difference between a statement and an expression in Kotlin is that an expression has a value and a statement does not.
- If the body of the function consists of a single expression, you can dispense with curly braces and return.
when
Reserved words are used for substitutionswitch-case
And it is an expression that returns the value of the last expression that hit the branch.- Kotlin introduced
property access syntax
Getters and setters are no longer required and you can assign values to properties directly. ? .
Referred to asSecure call operator, only if the calling variable is notnull
Otherwise the entire expression is returnednull
. This avoids defensive programming.?
Placing after a type indicates that a variable or return value of that type may benull
.- Kotlin uses extension functions to add methods to a class outside of the class.
- Kotlin preorders a number of extension functions, including one for “doing multiple operations on the same object.” including
also()
,apply()
,let()
,with()
.
Recently, I started to learn Kotlin. While reading “Kotlin Actual Combat”, I used it in projects. The series is constantly adding new discoveries from books and practice. Hope it can help you ~~
Recommended reading
- Kotlin base | entrusted and its application
- Kotlin basic grammar | refused to noise
- Kotlin advanced | not variant, covariant and inverter
- Kotlin combat | after a year, with Kotlin refactoring a custom controls
- Kotlin combat | kill shape with syntactic sugar XML file
- Kotlin base | literal-minded Kotlin set operations
- Kotlin source | magic weapon to reduce the complexity of code
- Why Kotlin coroutines | CoroutineContext designed indexed set? (a)
- Kotlin advanced | the use of asynchronous data stream Flow scenarios