在Android应用程序中享受传统-现代Java

前言

自 2019 年以来,Kotlin 是 Android 应用程序的首选语言。两年前,谷歌宣布在 Android Studio 中支持 Kotlin。从那时起已经过去了相当长的一段时间。那么,为什么 2021 年夏天的一篇文章仍然涉及Android 应用程序中的现代 Java ?

因为 Java 仍然存在于许多 Android 应用程序中。特别是在 2017 年之前发布的那些。当然,许多已经部分或完全转换为 Kotlin。但其他人没有。而且,应用程序越旧,使用的 Java 风格就越旧。Apache Harmony(其类库进入 Android)始于 Java 1.5。所以,非常古老的应用程序看起来像这样:大量的匿名内部类。StringJava 7的 s in switchstatements 或 try-with-resources 等功能需要很长时间才可AutoCloseable用。Java 8 的 Lambda 和流也没有立即可用。

因此,Android 应用程序中的 Java 代码可能看起来比它需要的要旧。我们当然可以说,只要该代码不会造成麻烦,我们最好不要管它。但如果它仍然是应用程序的重要组成部分,我们应该像对待新代码一样对待它:关心它。这可能意味着:

  • 将其转换为 Kotlin
  • 利用现代 Java 特性

我不打算比较这些方法,因为这本身就是一篇文章。😀 相反,我将专注于后一种选择。但在我们深入研究之前:这不是关于 Java 与 Kotlin,当然也不是关于争论哪种编程语言更好。我只是认为任何代码都应该尽可能好。

设置

语言版本在模块级build.gradle文件中配置。

android {
  ...
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_11
    targetCompatibility JavaVersion.VERSION_11
  }
  kotlinOptions {
    jvmTarget = '11'
    useIR = true
  }
  ...

要使用 Java 11,我们还需要配置Android Gradle 插件 7.0,顺便说一下,它需要Java 11。这是在项目级build.gradle文件中完成的。

buildscript {
  ...
  repositories {
    google()
    mavenCentral()
  }
  dependencies {
    classpath "com.android.tools.build:gradle:7.0.0"
    ...

但为什么是 Java 11?我们在 3 月份没有看到 Java 16 吗?Java 11 是继 Java 8 之后的第一个长期支持 (LTS) 版本。Oracle 于 2019 年 1 月停止支持 Java 8。下一个 LTS 版本将是 Java 17,计划于 2021 年 9 月发布。

有什么存货?

作为 Kotliner,我们喜欢写类似

var s = resources.getString(R.string.app_name)

或者val,如果s不改变。

从 Java 10开始,这也是可能的:

var s = context.getString(R.string.app_name);

如果需要,您可以进行s最终处理。我们在这里看到的称为局部类型推断。不错,不是吗?但是请记住,它不能在块、方法和构造函数之外工作。

Java 11 添加var了 lambda 参数。

var list = Arrays.asList("Hello", "Android");
var result = list.stream()
    .map((var x) -> x.toUpperCase(Locale.getDefault()))
    .collect(Collectors.joining(", "));

也有一些新的方法String:isBlank(), lines(), strip(), stripLeading(), stripTrailing(), 和repeat(). 遗憾的是,我们不能使用它们(在撰写本文时)。那是因为 Android 类库是 Java 类库和 Android 特定包的组合。对 OpenJDK 类库的更改不会自动成为 Android 的一部分。相反,它们是手工挑选的。实际上,每个 API 级别都会看到一些正在移植的更改。例如,使用 API 级别 31,我们将compareUnsigned()进入java.lang.Short. 它在 Java 9 中首次亮相。

甚至更老的是 try-with-resources:Java 7 中最酷、可能最少使用的特性之一。看看:

FileInputStream fis = null;
try {
  fis = context.openFileInput("myfile.txt");
  // do some work
} catch (FileNotFoundException e) {
  Log.e(TAG, "something went wrong", e);
}
if (fis != null) {
  try {
    fis.close();
  } catch (IOException e) {
    Log.e(TAG, "something went wrong", e);
  }
}

是的,这是样板代码。但是这个怎么样?

try (FileInputStream fis = context.openFileInput("myfile.txt")) {
  // do some work
} catch (IOException e) {
  Log.e(TAG, "something went wrong", e);
}

如果您想知道…不,我没有忘记close(). 这是自动完成的。下一个…

try {
  var fis = context.openFileInput("myfile.txt");
  // do some work
} catch (IOException e) {
  Log.e(TAG, "something went wrong", e);
} catch (IllegalArgumentException e) {
  Log.e(TAG, "something went wrong", e);
} catch (NullPointerException e) {
  Log.e(TAG, "something went wrong", e);
}

是的,这里肯定有问题。

为什么不这样呢?

try {
  var fis = context.openFileInput("myfile.txt");
} catch (IOException |
    IllegalArgumentException |
    NullPointerException e) {
  Log.e(TAG, "something went wrong", e);
}

从 Java 7 开始,一个catch块可以处理不止一种类型的异常。这可以减少代码重复。而且您不再有catching的解释Throwable。🤣

样板代码的另一个来源是匿名内部类

Button b = findViewById(R.id.button);
b.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View view) {
    // do some work
  }
});

我们可以将其缩小为:

Button b = findViewById(R.id.button);
b.setOnClickListener(view -> {
  // do some work
});

如您所见,Java 仍然面临的一些偏见(在某种程度上)不再有效。开发人员可以对其代码进行现代化改造。你可以做很多事情。

结论

对旧的 Java 代码进行现代化改造无疑是值得的。首先,它变得更容易阅读。其次,您将能够删除大量样板代码。第三,您的应用程序将变得不那么容易出错。不相信我?老实说,你的代码真的放在close()里面了吗try?catch…嗯,你应该。并且通过 try-with-resources 您可以免费获得它。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值