逆向kotlin转java,解毒 Kotlin Koans: 02 震惊!你的 Java 代码居然被转换成了这样......

0. 上期回顾

上回书我们说道,一个简单的 HelloWorld 背后也可以隐藏着众多不可告人的秘密。那么这些秘密究竟是什么呢?

那就是,只要我们写的代码可以支持下面的代码运行,并返回 "OK",那么这事儿就成啦:

start()

既然这样,我们除了可以有上一回提到的两种普通解法之外,还应该有以下几种高端解法:

默认参数法:fun start(str: String = "OK") = str

Lambda 表达式/匿名函数法val start = { "OK" }

运算符重载法object start{

operator fun invoke() = "OK"

}

你还想到什么有趣的解法了么?

1. 转换 Java 为 Kotlin

大家学习 Kotlin,一定知道有个神奇叫做 "Convert Java File to Kotlin File",不仅如此,如果你复制一段 Java 代码到 Kotlin 文件中,这段代码也会自动转换成 Kotlin 代码。

有很多时候如果你不知道某种东西怎么用 Kotlin 表达,怎么办呢?你总不能说:小二,给洒家来一本牛津大辞典吧?还好有 J2K 转换工具,这些问题有时候只要你会 Java,你就可以丧心病狂的转换出 Kotlin 代码。

我们今天按照 Kotlin Koan 给出的顺序,要解毒的就是下面这道题:

把下面这段 Java 代码转换为 Kotlin 代码:public class JavaCode {

public String toJSON(Collection collection) {

StringBuilder sb = new StringBuilder();

sb.append("[");

Iterator iterator = collection.iterator();

while (iterator.hasNext()) {

Integer element = iterator.next();

sb.append(element);

if (iterator.hasNext()) {

sb.append(", ");

}

}

sb.append("]");

return sb.toString();

}

}

嗯,老夫想了想,这有何难,复制粘贴谁不会,真是的。

ad658c7e7eedb486d020ddac04aa6a2c.gif

从此以后,我就成了 Kotlin 大神,反正只要用工具把 Java 代码转一下就好啦,还学什么学 >.

2. 什么玩意,空指针啊

后来我就经常需要将原来用 Java 编写的 Activity 转换为 Kotlin 版本的,例如:

public class TestActivity extends Activity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

...

}

}

老板说了,从今天起,谁写 Java 就是跟他作对(请允许我 YY 一下 - -、),于是没有办法,我就得把它转成 Kotlin:

class TestActivity : Activity() {

override fun onCreate(savedInstanceState: Bundle) {

super.onCreate(savedInstanceState)

...

}

}

转的挺快啊,我还没反应过来,就转完了!不过这代码你要是敢运行一遍,Crash 就敢恶心你一遍。savedInstanceState 这个参数可能为 null,显然类型定为 Bundle 有些不合适。

对于平台类型(Platform Type),很多时候转换工具是无从得知它是否可能为空的,毕竟 Java 没有对此作出过任何承诺。

怎么办?Kotlin 提供了一对注解来标注 Java 类型是否可空:@Nullable 和 @NotNull,Android Support Annotations 这个包也提供了一对:@Nullable 和 @NonNull,我们用这些注解标注一下 Java 类型,那么再做转换,工具就会根据你做的标注来转换代码。

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

...

}

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

...

}

一句话,用转换工具的时候一定要注意平台类型!

3. Raw 类型惨叫一声...

尽管我们知道这转换工具没办法有效识别平台类型的问题,不过,对于下面的情况,它支持起来可能就更有些尴尬了:

public class BaseView {

T presenter;

}

...

public class BasePresenter {

T view;

}

下面是转换后的结果:

class BaseView> {

var presenter: T? = null

}

class BasePresenter> {

var view: T? = null

}

看上去也没啥问题啊,为啥 IDE 就报错呢?因为我们要求 BaseView 当中的 T 类型是 BasePresenter 的子类,不过我们对这里的 BasePresenter 有个小小的要求,那就是它的泛型参数得是 BaseView 的子类而不是 *。对于 BasePresenter 也是一样的。

那么 Java 中为什么没有这样的问题呢?因为 Java 中有 Raw 类型,你可以不传任何泛型参数给 BaseView 就像我们在声明 BasePresenter 的时候那样。

显然,对于 Raw 类型的转换,转换工具会用 * 来代替,但这样的代码有时候可以,有时候却是行不通的。

小心 Raw 类型!

4. Kotlin 风格的代码

吐槽转换工具就好比我们吐槽谷歌翻译一样:有时候不对,就像我们在 2、3 两节举的例子一样,

22ecdfe5506c9de48ca2a030e48df649.png

有时候呢,虽然不算错,但也实在是别扭...

8d3658f8e7f135288be71fbed465a41a.png

比如我们今天提到的 Koans 的这道题目,代码转换的结果虽然是对的,但这代码直接暴露了你不会 Kotlin 的事实。会写 Kotlin 的人家都这么写:

fun toJSON(collection: Collection): String = collection.joinToString(separator = ", ", prefix = "[", postfix = "]")

不就是拼接字符串么,还用得着亲自动手?祭出 joinToString 神器,可以解决你日常 80% 的拼接需求了。

可是 Collection 怎么会有这么个方法,在 Java 里面没见过呀!于是你不相信这眼前的一切,点进去看了一下源码,就发现了扩展方法这样的大杀器,从此你的 Kotlin 装备增加了 100 点物理伤害,以及 40% 的攻速。

public fun Iterable.joinToString(...): String {

return joinTo(...).toString()

}

掌握扩展方法不需要太多的前置条件,只要你有过迫切的想法想给 Date 添加一个 format 的方法的冲动,那么你就能理解这个特性是用来做什么的。

fun Date.format(pattern: String): String {

return SimpleDateFormat(pattern).format(this)

}

...

Date().format("yyyy-MM-dd HH:mm:ss")

5. 本期问题

请大家阅读 Kotlin 泛型,并且给出第 3 节中提到的 BaseView 和 BasePresenter 的 Kotlin 的正确写法。

请大家为 String 添加扩展方法, 实现 "abc" - "bc" -> "a"

那么我们下周再见咯~

关注 Kotlin,就像关注每天吃啥一样~

其基础编译器(他们将其改为kompiler——开创了一系列以K字打头的用语——甚至连 contributors这类词他们也用改成了kontributors)可以被独立出来并嵌入到 Maven、Ant 或 Gradle 工具链中。这使得在 IDE 中开发的代码能够利用已有的机制来构建,从而尽可能的减少了在新环境中使用所受的干预,哪怕与那些没有安装 Kotlin 插件的开发人员一起合作项目也没有问题。 The IntelliJ Kotlin 插件扩展了 Java 编译器使得 Kotlin 代码能够得以编写、编译和调试。除此之外,关于基本的 Java 集合,已经有编写好的帮助函数,可以更顺畅地衔接将在 Java 8 中出现的集合扩展。 有两篇文章对 KotlinJava 以及 Kotlin 与 Scala 分别进行了比较,对各自特性和异同进行了对比。即便 Scala 可能还是更为强大些,Kotlin 还是尝试着提供比 Java 更好的函数、模式匹配、空指针预防和泛型。该语言同时也支持特征(traits)和模式匹配。 Kotlin 插件在当前版本的 IntelliJ 和 Eclipse 中均已能使用。 [4] Kotlin,类似 Xtend 一样,旨在提供一种更好的 Java 而非重建整个新平台。这两种语言都向下编译为字节码(虽然 Xtend 是首先转换成相应的 Java 代码,再让 Java 编译器完成繁重的工作),而且两者都引入了函数和扩展函数(在某个有限范围内静态地增加一个新方法到某个已有类型的能力)。Xtend 是基于 Eclipse 的,而 Kotlin 是基于 IntelliJ 的,两者都提供无界面构建。能够首先演变到其他 IDE 的语言有可能成为最后的赢家。
Kotlin中,`java.lang.NullPointerException: null cannot be cast to non-null type`是一个常见的运行时错误,它发生在尝试将null值换为非空类型(如引用类型)时。这是因为Kotlin是一种强类型语言,它不允许你对可能为null的对象执行非空类型的操作。 当你遇到这个错误时,通常意味着你在代码的某个地方尝试调用了一个方法或访问了一个属性,而该对象在运行时是null。例如: ```kotlin val myObject: MyNonNullClass? = null // 声明一个可为null的对象 myObject?.doSomething() // 这里会抛出异常,因为doSomething()期望myObject不为null // 或者在访问属性时 val myValue = myObject?.myProperty // 如果myObject为null,myProperty会被视为null,尝试访问会导致异常 ``` 解决这个问题的方法有几种: 1. 在调用或访问前进行安全检查:使用`?.`(safe call operator)来防止null安全问题,如果对象为null,表达式将返回null,不会抛出异常。 ```kotlin if (myObject != null) { myObject.doSomething() } ``` 2. 使用`also`扩展函数:当需要执行一些操作但不关心是否为null时,可以在null安全上下文中使用`also`。 ```kotlin myObject?.also { it.doSomething() } ``` 3. 初始化变量或方法参数时设置默认值:如果不确定值是否为null,可以在声明时设置默认值。 ```kotlin val myObject = myObject ?: MyNonNullClass() // 如果myObject为null,创建一个新的MyNonNullClass实例 ``` 4. 使用可空类型(nullable types):如果你确实希望某个变量可以是null,那么声明时使用`MyNonNullClass?`而不是`MyNonNullClass`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值