热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

你真的开始用JDK8了吗?(下)

上篇文章中,看到了JDK8中的Optional和LambdaExpressions带来编程上的改变,甚至编程思维的改变。接下来我们继续看JDK8的Stream和Interfaced

上篇文章中,看到了JDK8中的Optional和Lambda Expressions带来编程上的改变,甚至编程思维的改变。接下来我们继续看JDK8的Stream和Interface default method给我们带来的改变

Stream

Stream也是JAVA8的一大特点,这里的Stream和IO的那个Stream不同,它提供了对集合操作的增强,极大的提高了操作集合对象的便利性。下面我们就通过一个示例来看,使用Stream给我们带来哪些改变。

有一批学生考试数据,包括学生ID,班级ID,学科,分数。来计算如下指标

  1. 找出所有语文科目,分数大于60分的学生
  2. 找出语文科目,排名第一的学生
  3. 计算学生ID为10的学生的总分
  4. 所有学生按照总分从大到小

在JDK8之前,实现以上功能也非常简单的,相信对于一个刚刚学习Java的工程师来说,也很容易实现。不妨大家给自己设定一个限制,如何使用最少的代码实现以上功能。这里留作一个问题思考,下面我们使用Stream API来实现这些需求.

筛选:filter用法

找出所有语文科目,分数大于60分的学生

studentScores.stream()
.filter(s -> "语文".equals(s.getSubject()) && s.getScore() >= 60f)
.collect(Collectors.toList())
.forEach(System.out::println);

排序:sorted用法

找出语文科目,排名第一的学生

Optional studentScore = studentScores.stream()
.filter(s -> "语文".equals(s.getSubject()))
.sorted((s1, s2) -> s1.getScore() > s2.getScore() ? -1 : 1)
.findFirst();
if (studentScore.isPresent()) {
System.out.println(studentScore.get());
}

统计计算:reduce

计算学生ID为10的学生的总分

Double total = studentScores.stream()
.filter(s -> s.getStudentId() == 10)
.mapToDouble(StudentScore::getScore)
.reduce(0, Double::sum);
System.out.println(total);
分组统计:Collectors

所有学生按照总分从大到小

studentScores.stream()
.collect(Collectors.groupingBy(StudentScore::getStudentId
, Collectors.summingDouble(StudentScore::getScore)))
.entrySet()
.stream()
.sorted((o1, o2) -> o1.getValue() 1 : -1)
.forEach(System.out::println);

以上的示例已经包括了Stream API的大部分的功能。从以上可以看到,在进行计算时,总是需要使用在集合对象中使用stream()方法,先转成Stream然后在进行后面的操作,为什么不直接在集合类下直接实现如下操作呢?Stream和集合类有哪些区别?Oracle给出了如下说明

  1. Stream没有存储,它不是数据结构,并不保存数据。它可以像数组、生成器等数据源获取数据,通过一个计算流进行操作
  2. 在功能性质上,通过流的操作,不会修改数据源,比如,filter操作,是从集合的流上获取一个新的流,而不是将过滤掉的元素从集合上删除
  3. 延迟计算,许多流式的计算像filter、map等,是通过懒式的实现。一个数据流操作包括三个基本步骤,数据源->数据转换->执行获取结果。每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象。数据转换的操作都是lazy的
  4. 可以支持无限的大小。虽然集合是有限的,但是流是可以支持无限大小的,像limit(n)或者findFirst可以让无限的流操作在有限的时间内完成
  5. 流的元素只能在一次创建中被访问到一次,像Iterator一样,必须生成一个新的流来访问新的元素

Interface default method

在JDK8中,使用forEach方法可以直接遍历数组,当然们进入查看forEach查看源代码时,我们在Iterable接口可以看到如下代码:

default void forEach(Consumersuper T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}

这不是方法的实现么?是的,在接口里可以写实现了。在JDK8中为了支持新特性,必须对原有接口进行改造。需要在不破坏现有的架构情况下在接口里增加新方法。这也是JAVA8引入Default method的原因。但是引入Default method之后,需要思考两个问题:

和抽象类区别

当接口有了default method 之后,接口看起来和抽象性是一样的,但是他们两个在Java8中还是有区别的。

抽象类,有自己的构造方法,并且可以定义自己的数据结构,但是默认方法只能调用接口时使用,并不会涉及到特定接口实现类的状态。具体使用接口还是抽象类还需要根据具体业务场景来界定

接口的多继承问题

在java中可以支持多继承,如果两个接口实现了同样的默认方法,那么应该使用哪个呢?

比如:

public interface DemoA {

default void test() {
System.out.println("I'm DemoA.");
}
}

public interface DemoB {

default void test() {
System.out.println("I'm DemoB.");
}
}

如果一个DemoImpl继承以上两个接口,代码如下:

public class DemoImpl implements DemoA, DemoB {
}

这时,IDE会在DemoImpl下面有一条红线,提示不能继承在DemoA和DemoB中的test方法,需要实现该方法

public class DemoImpl implements DemoA, DemoB {
@Override
public void test() {
DemoB.super.test();
DemoA.super.test();;
}
}

实现该方法,和其他方式类似,你可以调用父类中的方法,也可以直接自己实现

Other features

除了以上的一些特性,JDK8中还支持了其他的一些特性值得关注

  1. 引入了新的Date-Time API(JSR 310)来改进时间、日期的处理。
  2. 引入新的Nashorn Javascript引擎,使得我们可以在JVM上开发和运行JS应用。
  3. 引入了Base64编码的支持
  4. 新增了支持数组的并行处理的parallelSort方法等等

欢迎关注我的公众号MyArtNote

MyArtNote


推荐阅读
  • 本文介绍了在 Java 编程中遇到的一个常见错误:对象无法转换为 long 类型,并提供了详细的解决方案。 ... [详细]
  • 本文探讨了如何利用Java代码获取当前本地操作系统中正在运行的进程列表及其详细信息。通过引入必要的包和类,开发者可以轻松地实现这一功能,为系统监控和管理提供有力支持。示例代码展示了具体实现方法,适用于需要了解系统进程状态的开发人员。 ... [详细]
  • 本文将带你快速了解 SpringMVC 框架的基本使用方法,通过实现一个简单的 Controller 并在浏览器中访问,展示 SpringMVC 的强大与简便。 ... [详细]
  • DAO(Data Access Object)模式是一种用于抽象和封装所有对数据库或其他持久化机制访问的方法,它通过提供一个统一的接口来隐藏底层数据访问的复杂性。 ... [详细]
  • 本文探讨了如何在 Java 中将多参数方法通过 Lambda 表达式传递给一个接受 List 的 Function。具体分析了 `OrderUtil` 类中的 `runInBatches` 方法及其使用场景。 ... [详细]
  • oracle c3p0 dword 60,web_day10 dbcp c3p0 dbutils
    createdatabasemydbcharactersetutf8;alertdatabasemydbcharactersetutf8;1.自定义连接池为了不去经常创建连接和释放 ... [详细]
  • 大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式
    大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式 ... [详细]
  • 属性类 `Properties` 是 `Hashtable` 类的子类,用于存储键值对形式的数据。该类在 Java 中广泛应用于配置文件的读取与写入,支持字符串类型的键和值。通过 `Properties` 类,开发者可以方便地进行配置信息的管理,确保应用程序的灵活性和可维护性。此外,`Properties` 类还提供了加载和保存属性文件的方法,使其在实际开发中具有较高的实用价值。 ... [详细]
  • 在Java编程中,初始化List集合有多种高效的方法。本文介绍了六种常见的技术,包括使用常规方式、Arrays.asList、Collections.addAll、Java 8的Stream API、双重大括号初始化以及使用List.of。每种方法都有其特定的应用场景和优缺点,开发者可以根据实际需求选择最合适的方式。例如,常规方式通过直接创建ArrayList对象并逐个添加元素,适用于需要动态修改列表的情况;而List.of则提供了一种简洁的不可变列表初始化方式,适合于固定数据集的场景。 ... [详细]
  • Flowable 流程图路径与节点展示:已执行节点高亮红色标记,增强可视化效果
    在Flowable流程图中,通常仅显示当前节点,而路径则需自行获取。特别是在多次驳回的情况下,节点可能会出现混乱。本文重点探讨了如何准确地展示流程图效果,包括已结束的流程和正在执行的流程。具体实现方法包括生成带有高亮红色标记的图片,以增强可视化效果,确保用户能够清晰地了解每个节点的状态。 ... [详细]
  • Spring框架中枚举参数的正确使用方法与技巧
    本文详细阐述了在Spring Boot框架中正确使用枚举参数的方法与技巧,旨在帮助开发者更高效地掌握和应用枚举类型的数据传递,适合对Spring Boot感兴趣的读者深入学习。 ... [详细]
  • 使用 ListView 浏览安卓系统中的回收站文件 ... [详细]
  • 本文详细介绍了在 Oracle 数据库中使用 MyBatis 实现增删改查操作的方法。针对查询操作,文章解释了如何通过创建字段映射来处理数据库字段风格与 Java 对象之间的差异,确保查询结果能够正确映射到持久层对象。此外,还探讨了插入、更新和删除操作的具体实现及其最佳实践,帮助开发者高效地管理和操作 Oracle 数据库中的数据。 ... [详细]
  • 在处理 XML 数据时,如果需要解析 `` 标签的内容,可以采用 Pull 解析方法。Pull 解析是一种高效的 XML 解析方式,适用于流式数据处理。具体实现中,可以通过 Java 的 `XmlPullParser` 或其他类似的库来逐步读取和解析 XML 文档中的 `` 元素。这样不仅能够提高解析效率,还能减少内存占用。本文将详细介绍如何使用 Pull 解析方法来提取 `` 标签的内容,并提供一个示例代码,帮助开发者快速解决问题。 ... [详细]
  • 使用Maven JAR插件将单个或多个文件及其依赖项合并为一个可引用的JAR包
    本文介绍了如何利用Maven中的maven-assembly-plugin插件将单个或多个Java文件及其依赖项打包成一个可引用的JAR文件。首先,需要创建一个新的Maven项目,并将待打包的Java文件复制到该项目中。通过配置maven-assembly-plugin,可以实现将所有文件及其依赖项合并为一个独立的JAR包,方便在其他项目中引用和使用。此外,该方法还支持自定义装配描述符,以满足不同场景下的需求。 ... [详细]
author-avatar
茶不离
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有