跳到主要内容 Kotlin 基础:拒绝语法噪音 | 极客日志
Kotlin 大前端 java
Kotlin 基础:拒绝语法噪音 Kotlin 语言致力于降低代码复杂度,通过一系列语法特性减少语法噪音。本文从 Java 开发者视角出发,对比展示了 Kotlin 在变量声明、继承重写、Lambda 表达式、属性访问、空安全调用及扩展函数等方面的优势。重点介绍了 var/val 类型推导、open 修饰符、when 表达式、?.安全调用运算符以及 apply/also/let 等作用域函数的用法,并通过实际案例演示了如何利用 Kotlin 特性简化 Android 开发中的 View 动画与点击事件处理逻辑。
字节跳动 发布于 2025/2/7 更新于 2026/4/19 1 浏览程序员最头痛的事莫过于看不懂别人的代码。缘由是各式各样的,但归结于一点就是复杂度太高。Kotlin 在降低代码复杂度上下了大功夫,运用一系列新的语法特性降低语法噪音,以求更简单直白地表达语义。
这篇以一个刚从 Java 转到 Kotlin 程序员的视角分享下 Kotlin 给我的第一印象。
无需 new 和分号
新建对象不需要 new 关键词。
任何语句的结尾不需要分号,但加上也不会有语法错误。
var buffer = StringBuffer()
var 是 Kotlin 保留字,用于声明变量。与之对应的是 val 用于声明常量,常量意思是引用不可变,但并不代表其引用对象也不可变。
不需要显示指明变量类型,因为 Kotlin 会根据上下文推断变量类型,这种能力称为'类型推导'。
可以通过下面的语法来指定类型:
var buffer: StringBuffer = StringBuffer()
Kotlin 中类型是后置的,在变量名后跟上:类型就可以显示指定类型。同理,它也用于指定函数返回值类型:
fun getMessage () : String {
return "message"
}
继承与重写
public class CheckableActivity extends Activity {
final public void setStatus () {}
}
public class MyListener implements View .OnClickListener {
@Override
public void onClick (View v) {}
}
class CirclePartyListActivity : Activity () {
{}
}
: {
{}
}
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
fun setStatus ()
class
MyListener
View.OnClickListener
override
fun onClick (v: View ?)
Kotlin 用:取代了 implements 和 extends 保留字。
@Override 也被 override 保留字取代并且和函数头同行,Kotlin 中的 override 是必须的,而 Java 中是可选的。
Kotlin 中类和方法默认是 final 的(可省略不写),这意味着默认情况下,类和方法是不允许被继承和重写的(这是为了防止脆弱的基类,即对基类方法的修改会导致子类出现预期之外的行为)。只有通过 open 保留字显示声明该类或方法可以被继承或重写:
open class A {
open fun do () {}
}
Lambda 简化
view.setOnClickListener({ v -> v.visibility = View.INVISIBLE })
view.setOnClickListener { v -> v.visibility = View.INVISIBLE }
view.setOnClickListener { v -> v.visibility = View.INVISIBLE }
view.setOnClickListener { it.visibility = View.INVISIBLE }
属性访问 Java 中,字段和其访问器的组合被称为属性,Kotlin 引入了 property access syntax,它取代了字段和访问器方法,用这种方式进一步简化上面的代码:
view.setOnClickListener { it.visibility = View.INVISIBLE }
所有被定义了 getter 和 setter 方法的字段,在 Kotlin 中都可以通过赋值语法来操作。
表达式函数体 Kotlin 中的语句和表达式的唯一区别是:表达式有值,而语句没有。如果函数体由单个表达式构成,可以省去花括号和 return,并用赋值的=表示将表达式的值赋值给返回值,这种语法叫表达式函数体:
fun add (a: Int , b: Int ) : Int = a + b
在 lambda 表达式中包含多条语句或表达式时,若省略 return,则默认将最后一个表达式的值作为返回值:
view.setOnTouchListener { v, event ->
false
}
上述代码表示在 OnTouchListener.onTouch() 中返回 false。
When 表达式
String color;
switch (colorInt) {
case Color.RED:
color = "red" ;
break ;
case Color.BLUE:
color = "blue" ;
break ;
default :
color = "black" ;
break ;
}
val color = when (colorInt) {
Color.RED -> "red"
Color.BLUE -> "blue"
else -> "black"
}
when 用于取代 switch-case,不需要在每个分支末尾调用 break,如果有一个分支命中则会立即返回。
when 是一个表达式,这意味着它有返回值,返回值等于命中分支中最后一条语句的返回值。
接口默认实现 Java 中的 default 保留字用于接口中默认方法的实现。在 Kotlin 中可以省去它。
public interface IMessage {
default String getMessage () {
return "default message" ;
}
int getMessageId () ;
}
interface IMessage {
fun getMessage () : String {
return "default message"
}
fun getMessageId () : Int
}
Int 是 Java 中基本数据类型 int 的包装类,Kotlin 中没有基本数据类型。
空安全与防御式编程
public class Address {
private String country;
public String getCountry () {
return country;
}
}
public class Company {
private Address address;
public Address getAddress () {
return address;
}
}
public class Person {
private Company company;
public String getCountry () {
String country = null ;
if (company != null ) {
if (company.getAddress() != null ) {
country = company.getAddress().getCountry();
}
}
return country;
}
}
fun Person.getCountry () : String? {
return this .company?.address?.country
}
?.称为安全调用运算符,它把判空检查和一次方法调用合并成一个操作。只有当调用变量不为 null 时,才会执行调用,否则整个表达式返回 null。这意味着,不再需要防御式编程。
?置于类型之后表示这个类型可空,上面的函数声明表示此函数的返回值可能为 null。
上面的 Kotlin 代码为 Person 类添加了一个 getCountry() 方法,这种技术叫扩展函数。
扩展函数 扩展函数是一个类的成员函数,但它定义在类体外面。这样定义的好处是,可以在任何时候任何地方给类添加功能。
在扩展函数中,可以像类的其他成员函数一样访问类的属性和方法(除了被 private 和 protected 修饰的成员)。还可以通过 this 引用类的实例,也可以省略它,把上段代码进一步简化:
fun Person.getCountry () : String? {
return company?.address?.country
}
Kotlin 预定了很多扩展函数,下面就会用到其中的 apply:
作用域函数 编程中经常会遇到'对同一个对象做多次操作'的场景,比如:
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);
其中,对象 intent 和 bundle 重复出现若干次,这对于极简主义的 Kotlin 来说不能忍,它的表达方式如下:
Intent(this , Activity1::class .java).apply {
action = "actionA"
putExtras(Bundle().apply {
putString("content" , "hello" )
putString("sender" , "taylor" )
})
startActivity(this )
}
public inline fun <T> T.apply (block: T .() -> Unit ) : T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
对于 object.apply{lambda}可以简单的理解为:在 object 对象上应用 lambda 操作,并且最终返回 object 对象本身。所以上述代码也可以写成更加紧凑的形式:
startActivity(Intent(this , Activity1::class .java).apply {
action = "actionA"
putExtras(Bundle().apply {
putString("content" , "hello" )
putString("sender" , "taylor" )
})
})
同一类型的预定义扩展函数还包括 with、let、also。它们的共同点是适用于'对同一个对象做多次操作'的场景。
Kotlin 中,发起调用扩展函数的那个对象,叫接收者对象。同理,发起调用 lambda 的对象叫做 lambda 接收者。
可以将 also 的源码和 apply 做对比,更好的理解他们调用者角色的差别:
public inline fun <T> T.also (block: (T ) -> Unit ) : T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block(this )
return this
}
综合应用 '让 app 中所有被点击的 View 都带上缩放动画'。综合运用上述 Kotlin 知识点实现这个需求之前,先来看看 Java 是如何实现的:
先定义工具类,该工具类为传入的 View 分别设置触摸和单击监听器。在按下时播放动画,松手时反向播放动画。
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 ;
}
return false ;
}
});
view.setOnClickListener(new View .OnClickListener() {
@Override
public void onClick (View v) {
if (listener != null ) {
listener.onClick(v);
}
}
});
}
}
在界面中新建动画和点击响应逻辑并将它们传递给工具类。
Button btn3 = findViewById(R.id.btn3);
ValueAnimator animator = ValueAnimator.ofFloat(1.0f , 1.2f );
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);
}
});
View.OnClickListener onClickListener = new View .OnClickListener() {
@Override
public void onClick (View v) {
Toast.makeText(Activity1.this , "spring anim" , Toast.LENGTH_LONG).show();
}
};
ViewUtil.addExtraAnimClickListener(btn3, animator, onClickListener);
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 ) }
}
btnSpringAnim.extraAnimClickListener(ValueAnimator.ofFloat(1.0f , 1.15f ).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() }
btnSpringAnim 是一个 Button 控件的 id(只要装了 kotlin 插件,就不需要 findViewById())
as 保留字用于类型强制转换。
Kotlin 凭借着极强的表达力用将近 1/3 的代码量完成了功能。
知识点总结
var 保留词用于声明变量,val 保留词用于声明常量。大多数情况下不需要显示指明变量类型,Kotlin 具有类型推导能力,会根据上下文自动推断类型。
fun 保留字用于声明函数。
override 保留字表示重写父类方法或者实现接口中的抽象方法,与 Java 不同的是,它必须显示出现在重写方法前(Java 允许省略)。
as 保留字用于类型强制转换。
Kotlin 中类型是后置的,在变量名或函数参数列表后跟上:类型就可以显示指定类型。
:还用于继承类(取代 extends)、实现接口(取代 implements)。
新建对象时不需要 new,而是直接调用构造函数。
语句末尾不需要;但加上也不会有语法错误。
Kotlin 中类和方法默认是 final 的,他们不能被继承和重写。只有通过加上 open 后才能被继承和重写。
Kotlin 中没有基本数据类型,而是用其对应的包装类表示。
给接口方法添加默认实现时不需要 default 关键字。
Kotlin 中的语句和表达式的唯一区别是:表达式有值,而语句没有。
如果函数体由单个表达式构成,可以省去花括号和 return。
when 保留字用于取代 switch-case,而且它是一个表达式,返回值是命中分支中最后一表达式的值。
Kotlin 引入了 property access syntax,不再需要 getter 和 setter 方法,可以直接对属性赋值。
?.称为安全调用运算符,只有当调用变量不为 null 时,才会执行调用,否则整个表达式返回 null。这样就避免了防御式编程。
?置于类型之后表示这个类型的变量或返回值可能为 null。
Kotlin 使用扩展函数,可以在类体外给类新增方法。
Kotlin 预定了很多扩展函数,其中有一类适用于'对同一个对象做多次操作'。包括 also()、apply()、let()、with()。