JavaRush /Java 博客 /Random-ZH /从 8 到 13:Java 版本的完整概述。第1部分

从 8 到 13:Java 版本的完整概述。第1部分

已在 Random-ZH 群组中发布
小猫们,大家好))所以,今天已经是 2020 年了,距离 Java 14 的发布已经所剩无几了。你应该期待 3 月 17 日的完成版本,事后我们会分析其中有哪些新鲜有趣的内容,但今天我想回顾一下以前的 Java 版本。他们给我们带来了什么新鲜事?我们来看看吧。让我们从 Java 8 开始回顾,因为它仍然非常相关并且在大多数项目中都使用。 从 8 到 13:Java 版本的完整概述。 第 1 - 1 部分此前,每 3-5 年发布一次新版本,但最近 Oracle 采取了不同的做法——“每六个月发布一个新 Java”。因此,每六个月我们就会看到功能的发布。不管是好是坏,每个人的看法都不一样。比如说,我就不太喜欢这个,因为新版本没有太多新功能,但与此同时,版本却如雨后春笋般生长。我在一个 Java 8 的项目上眨了几下眼,Java 16 已经发布了(但是当它很少出现时,新功能就会积累起来,最后这个事件就像一个假期一样期待已久:每个人都在讨论新的好东西,你不能错过它)。那么让我们开始吧!

爪哇8

功能接口

这是什么?函数式接口是包含一个未实现(抽象)方法的接口。 @FunctionalInterface是一个可选注释,放置在此类接口之上。需要检查它是否满足功能接口的要求(只有一个抽象方法)。但与往常一样,我们有一些警告:默认方法和静态方法不符合这些要求。因此,可以有多个这样的方法+一个抽象方法,并且该接口将是函数式的。它还可能包含 Object 类的方法,这些方法不会影响接口的功能定义。我将添加一些关于默认和静态方法的内容:
  1. 具有default修饰符的方法允许您向接口添加新方法,而不会破坏其现有实现。

    public interface Something {
      default void someMethod {
          System.out.println("Some text......");
      }
    }

    是的,是的,我们将实现的方法添加到接口中,并且在实现这个方法时,不能覆盖它,而是将其作为继承的方法使用。但是,如果一个类使用给定的方法实现了两个接口,我们将会遇到编译错误,并且如果它实现了接口并继承了具有某个相同方法的类,则父类方法将与接口方法重叠,并且异常将不起作用。

  2. 接口中的静态方法与类中的静态方法的工作方式相同。不要忘记:您不能继承静态方法,就像您不能从后代类调用静态方法一样。

那么,再多说几句关于函数式接口的内容,然后让我们继续。以下是主要的金融机构列表(其余是其品种):

    谓词 - 采用某个值 T 作为参数,返回布尔值。

    例子:boolean someMethod(T t);

  • Consumer - 接受 T 类型的参数,不返回任何内容 (void)。

    例子:void someMethod(T t);

  • 供应商 - 不接受任何输入,但返回一些值 T。

    例子:T someMethod();

  • 函数 - 将 T 类型的参数作为输入,返回 R 类型的值。

    例子:R someMethod(T t);

  • UnaryOperator - 接受 T 参数并返回 T 类型的值。

    例子:T someMethod(T t);

溪流

流是一种以函数式方式处理数据结构的方法。通常这些是集合(但您可以在其他不太常见的情况下使用它们)。用更容易理解的语言来说,Stream 是一种数据流,我们处理它时就像同时处理所有数据一样,而不是像 for-each 那样使用蛮力。让我们看一个小例子。假设我们有一组要过滤的数字(小于 50),增加 5,并将剩余数字中的前 4 个数字输出到控制台。早些时候我们会如何做:
List<Integer> list = Arrays.asList(46, 34, 24, 93, 91, 1, 34, 94);

int count = 0;

for (int x : list) {

  if (x >= 50) continue;

  x += 5;

  count++;

  if (count > 4) break;

  System.out.print(x);

}
看起来代码不多,逻辑已经有点混乱了。让我们看看使用流会是什么样子:
Stream.of(46, 34, 24, 93, 91, 1, 34, 94)

      .filter(x -> x < 50)

      .map(x -> x + 5)

      .limit(4)

      .forEach(System.out::print);
流通过减少代码量并使其更具可读性,极大地简化了生活。对于那些想要更详细地深入研究这个主题的人,这里有一篇关于这个主题的好(我什至可以说很棒)的文章

拉姆达

也许最重要和期待已久的功能是 lambda 的出现。 什么是拉姆达?这是一个可以传递到不同位置的代码块,因此可以根据需要多次执行。听起来很令人困惑,不是吗?简单地说,使用 lambda,您可以实现函数式接口的方法(匿名类的一种实现):
Runnable runnable = () -> { System.out.println("I'm running !");};

new Thread(runnable).start();
我们快速实现了 run() 方法,没有不必要的繁文缛节。是的:Runnable 是一个函数式接口。我在处理流时也会使用 lambda(如上面的流示例)。我们不会太深,因为我们可以深入得很深,我会留下几个链接,以便那些仍然是挖掘者的人可以深入挖掘:

foreach

Java 8 有一个新的 foreach,它可以像流一样处理数据流。这是一个例子:
List<Integer> someList = Arrays.asList(1, 3, 5, 7, 9);

someList.forEach(x -> System.out.println(x));
(类似于 someList.stream().foreach(...))

方法参考

引用方法是一种新的、有用的语法,旨在通过 :: 引用 Java 类或对象的现有方法或构造函数。方法引用有四种类型:
  1. 设计师链接:

    SomeObject obj = SomeObject::new

  2. 静态方法参考:

    SomeObject::someStaticMethod

  3. 对某种类型对象的非静态方法的引用:

    SomeObject::someMethod

  4. 对特定对象的常规(非静态)方法的引用

    obj::someMethod

通常,在流中使用方法引用而不是 lambda(引用方法比 lambda 更快,但可读性较差)。
someList.stream()

        .map(String::toUpperCase)

      .forEach(System.out::println);
对于那些想了解有关参考方法的更多信息的人:

API时间

有一个用于处理日期和时间的新库 - java.time。 从 8 到 13:Java 版本的完整概述。 第 1 - 2 部分新的 API 与任何 Joda-Time 类似。该 API 最重要的部分是:
  • LocalDate是一个具体日期,例如 - 2010-01-09;
  • LocalTime - 考虑时区的时间 - 19:45:55(类似于 LocalDate);
  • LocalDateTime - 组合 LocalDate + LocalTime - 2020-01-04 15:37:47;
  • ZoneId - 代表时区;
  • 时钟- 使用此类型您可以访问当前时间和日期。
这里有几篇关于这个主题的非常有趣的文章:

选修的

这是java.util包中的一个新类,它是一个值包装器,其技巧是它也可以安全地包含null。接收可选: 如果我们Optional<String> someOptional = Optional.of("Something");Optional.of中传递null,我们将得到我们最喜欢的NullPointerException。对于这种情况,他们使用: Optional<String> someOptional = Optional.ofNullable("Something"); - 在这种方法中,您不必担心 null。接下来,创建一个最初为空的Optional: Optional<String> someOptional = Optional.empty(); 要检查它是否为空,请使用: someOptional.isPresent(); 将向我们返回true或false。如果有值则执行某个操作,如果没有值则不执行任何操作:如果 someOptional.ifPresent(System.out::println); Optional为空则返回传递的值的反向方法(有点备份计划): System.out.println(someOptional.orElse("Some default content")); 您可以继续非常非常长的时间(幸运的是,Optional 慷慨地添加了方法),但我们不会详细讨论这一点。我最好为初学者留下几个链接: 我们回顾了 Java 8 中最著名的创新——这还不是全部。如果你想了解更多,那么我给你留下了这个:

爪哇9

因此,2017 年 9 月 21 日,全世界看到了 JDK 9。这个 Java 9 具有丰富的功能。虽然没有新的语言概念,但新的 API 和诊断命令肯定会引起开发人员的兴趣。 从 8 到 13:Java 版本的完整概述。 第 1 - 4 部分

JShell(REPL - 读取-评估-打印循环)

这是交互式控制台的 Java 实现,用于测试功能并在控制台中使用不同的构造,例如接口、类、枚举、运算符等。要启动JShell,您只需在终端中编写 jshell 即可。然后我们可以编写任何我们想象的内容: 从 8 到 13:Java 版本的完整概述。 第 1 - 5 部分使用 JShell,您可以创建顶级方法并在同一会话中使用它们。这些方法的工作方式与静态方法一样,只是可以省略static关键字。请阅读Java 9 REPL (JShell) 手册来了解更多信息。

私人的

从 Java 版本 9 开始,我们有机会在接口中使用私有方法(默认方法和静态方法,因为由于访问权限不足,我们根本无法覆盖其他方法)。 private static void someMethod(){} try-with-resources 处理 Try-With-Resources 异常的能力已升级:
BufferedReader reader = new BufferedReader(new FileReader("....."));
  try (reader2) {
  ....
}

模块化(拼图

模块是一组相关的包和资源以及新的模块描述符文件。这种方法用于放松代码的耦合。松耦合是代码可维护性和可扩展性的关键因素。模块化在不同层面上实现:
  1. 编程语言。
  2. 虚拟机。
  3. 标准java API。
JDK 9 附带 92 个模块:我们可以使用它们或创建自己的模块。以下是一些可以更深入了解的链接:

不可变集合

在Java 9中,可以用一行创建和填充集合,同时使其不可变(以前,要创建不可变集合,我们需要创建一个集合,用数据填充它,然后调用一个方法,例如,集合.不可修改列表)。这种创作的一个例子: List someList = List.of("first","second","third");

其他创新:

  • 扩展可选(添加新方法);
  • ProcessHandle 和 ProcessHandle 接口似乎用于控制操作系统的操作;
  • G1——默认垃圾收集器;
  • 支持 HTTP/2 协议和 WebSocket 的 HTTP 客户端;
  • 扩展流;
  • 添加了 Reactive Streams API 框架(用于反应式编程);
为了更完整地沉浸在 Java 9 中,我建议您阅读:

爪哇10

因此,在 Java 9 发布六个月后,即 2018 年 3 月(我记得就像昨天一样),Java 10 出现了。 从 8 到 13:Java 版本的完整概述。 第 1 - 6 部分

变量

现在我们不必提供数据类型。我们将消息标记为 var,编译器根据右侧初始化程序的类型确定消息的类型。此功能仅适用于具有初始值设定项的局部变量:它不能用于方法参数、返回类型等,因为没有能够定义类型的初始值设定项。示例 var(对于 String 类型):
var message = "Some message…..";
System.out.println(message);
var 不是关键字:它本质上是一个保留的类型名称,就像int一样。var的好处很大:类型声明占用了很多注意力,却没有带来任何好处,而且这个功能会节省时间。但与此同时,如果从一长串方法中获取变量,代码的可读性就会降低,因为我们立即不清楚那里是什么类型的对象。献给那些想要更熟悉此功能的人:

JIT 编译器 (GraalVM)

言归正传,让我提醒您,当您运行 javac 命令时,Java 应用程序将从 Java 代码编译为 JVM 字节码,这是应用程序的二进制表示形式。但常规计算机处理器不能简单地执行 JVM 字节码。为了让 JVM 程序正常工作,您需要另一个编译器来编译该字节码,将其转换为处理器已经能够使用的机器代码。与 javac 相比,该编译器要复杂得多,但也会生成更高质量的机器代码。目前,OpenJDK包含 HotSpot 虚拟机,而该虚拟机又具有两个主要的 JIT 编译器。第一个是 C1(客户端编译器),专为更高速度的操作而设计,但代码优化受到影响。第二个是C2(服务器编译器)。执行速度受到影响,但代码更加优化。什么时候使用哪一个?C1 非常适合桌面应用程序,因为长时间的 JIT 暂停是不受欢迎的,而 C2 非常适合长时间运行的服务器程序,因为在编译上花费更多时间是可以忍受的。 多级编译是编译首先经过C1,结果再经过C2(用于更大程度的优化)。 GraalVM是一个为了完全取代 HotSpot 而创建的项目。我们可以将 Graal 视为几个相关项目:一个新的 HotSpot JIT 编译器和一个新的多语言虚拟机。这个 JIT 编译器的独特之处在于它是用 Java 编写的。Graal编译器的优点是安全,即不会崩溃,不会出现异常,不会内存泄漏。我们还将拥有良好的 IDE 支持,并且我们将能够使用调试器、分析器或其他方便的工具。此外,编译器很可能独立于 HotSpot,并且它将能够创建自身更快的 JIT 编译版本。 对于挖掘机:

平行G1

G1 垃圾收集器确实很酷,这是毫无疑问的,但它也有一个弱点:它执行单线程完整 GC 周期。当您需要使用所有硬件功能来查找未使用的对象时,我们仅限于单个线程。Java 10 修复了这个问题。现在 GC 现在可以使用我们添加到其中的所有资源(也就是说,它变成了多线程)。为了实现这一目标,语言开发人员改进了主要源与 GC 的隔离,为 GC 创建了一个漂亮、干净的接口。这个可爱的开发者 OpenJDK 必须专门清理代码中的转储,以便不仅尽可能简化新 GC 的创建,而且还可以快速禁用程序集中不必要的 GC。成功的主要标准之一是在所有这些改进之后运行速度没有下降。 我们还看一下: 其他创新:
  1. 引入了干净的垃圾收集器接口。这改善了源代码与不同垃圾收集器的隔离,从而可以快速、轻松地集成替代收集器;
  2. 将 JDK 源合并到一个存储库中;
  3. Collections 收到了一个新方法 - copyOf (Collection),它返回此集合的不可变副本;
  4. Optional(及其变体)有一个新方法.orElseThrow()
  5. 从现在开始,JVM 知道它们正在 Docker 容器中运行,并将检索容器特定的配置,而不是查询操作系统本身。
以下是一些更详细介绍 Java 10 的材料: 我曾经对 Java 的某些版本被称为 1.x 这一事实感到非常困惑。我想澄清一下:Java 9 之前的版本只是有不同的命名方案。例如,Java 8 也可以称为1.8、Java 5 - 1.5等。现在我们看到,随着从 Java 9 过渡到版本,命名方案也发生了变化,Java 版本不再以 1.x 为前缀。第一部分到此结束:我们回顾了 java 8-10 的新的有趣特性。让我们在下一篇文章中继续了解最新的情况。
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION