0

0

JavaFX ObservableList中自定义对象属性计数教程

霞舞

霞舞

发布时间:2025-11-06 14:50:01

|

728人浏览过

|

来源于php中文网

原创

JavaFX ObservableList中自定义对象属性计数教程

本教程详细介绍了如何在javafx的`observablelist`中,高效统计自定义对象某个属性(如`id`)的出现次数。文章将演示两种主要方法:传统的迭代结合`hashmap`实现计数,以及更现代、简洁的java stream api结合`collectors.groupingby`和`counting()`进行聚合统计,并提供详细代码示例和解释,帮助开发者选择最适合其场景的解决方案。

在Java应用程序开发中,尤其是在使用JavaFX构建UI时,经常会遇到需要处理包含自定义对象的列表数据。一个常见的需求是统计列表中某个特定属性(例如一个对象的ID)的出现频率。本文将以ObservableList<CustomClass>为例,深入探讨如何有效地实现这一目标。

1. 定义自定义类与数据准备

首先,我们需要定义一个简单的自定义类CustomClass,它包含我们将要统计的属性。

public class CustomClass {
    public String id;
    public String name;

    // 建议添加构造函数和getter/setter方法以遵循良好的Java实践
    public CustomClass(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "CustomClass{" +
               "id='" + id + '\'' +
               ", name='" + name + '\'' +
               '}';
    }
}

接下来,我们模拟一个ObservableList<CustomClass>的创建和填充过程。这通常涉及到从文件、数据库或其他数据源读取数据并将其封装到自定义对象中。

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

import java.util.ArrayList;
import java.util.List;

public class DataInitializer {

    public static ObservableList<CustomClass> initializeList() {
        ObservableList<CustomClass> list = FXCollections.observableArrayList();

        // 模拟从文件读取的行数据
        List<String> rawLines = new ArrayList<>();
        rawLines.add("1/data1");
        rawLines.add("1/data2");
        rawLines.add("1/data3");
        rawLines.add("2/data1");
        rawLines.add("2/data2");
        rawLines.add("3/dataA");
        rawLines.add("1/data4"); // 再次出现id=1

        for (String s : rawLines) {
            String[] parts = s.split("/");
            if (parts.length == 2) {
                list.add(new CustomClass(parts[0], parts[1]));
            }
        }
        return list;
    }

    public static void main(String[] args) {
        ObservableList<CustomClass> myCustomList = initializeList();
        System.out.println("初始列表内容:");
        myCustomList.forEach(System.out::println);
        // 预期输出:
        // CustomClass{id='1', name='data1'}
        // CustomClass{id='1', name='data2'}
        // CustomClass{id='1', name='data3'}
        // CustomClass{id='2', name='data1'}
        // CustomClass{id='2', name='data2'}
        // CustomClass{id='3', name='dataA'}
        // CustomClass{id='1', name='data4'}
    }
}

2. 传统迭代方法实现计数

最直观的方法是遍历ObservableList,并使用一个HashMap来存储每个id及其对应的计数。当遍历到每个CustomClass对象时,我们检查其id是否已存在于HashMap中。如果存在,则将其计数加一;如果不存在,则将其添加进去并初始化计数为一。

立即学习Java免费学习笔记(深入)”;

import javafx.collections.ObservableList;
import java.util.HashMap;
import java.util.Map;

public class CountItemsIterative {

    public static Map<String, Integer> countByIdIterative(ObservableList<CustomClass> list) {
        Map<String, Integer> idCounts = new HashMap<>();
        for (CustomClass item : list) {
            String id = item.getId(); // 使用getter方法获取id
            idCounts.put(id, idCounts.getOrDefault(id, 0) + 1);
        }
        return idCounts;
    }

    public static void main(String[] args) {
        ObservableList<CustomClass> myCustomList = DataInitializer.initializeList();
        Map<String, Integer> counts = countByIdIterative(myCustomList);

        System.out.println("\n迭代方法计数结果:");
        counts.forEach((id, count) -> System.out.println("id=" + id + ", count=" + count));
        // 预期输出:
        // id=1, count=4
        // id=2, count=2
        // id=3, count=1
    }
}

代码解析:

  • HashMap<String, Integer> idCounts:用于存储id(键)和其出现次数(值)。
  • for (CustomClass item : list):标准的增强for循环,遍历ObservableList中的每个CustomClass对象。
  • item.getId():获取当前对象的id值。
  • idCounts.put(id, idCounts.getOrDefault(id, 0) + 1):这是核心逻辑。
    • getOrDefault(id, 0):尝试获取id对应的当前计数。如果id不存在,则返回默认值0。
    • 然后将获取到的值加1,并使用put方法更新或添加id及其新计数。

这种方法简单直观,易于理解,对于中小型数据集而言性能良好。

3. 使用Java Stream API进行高效计数

Java 8引入的Stream API提供了一种更函数式、更简洁的方式来处理集合数据。对于计数和分组这类操作,Stream API结合Collectors类提供了非常强大的工具。我们可以使用groupingBy收集器来根据id对对象进行分组,然后使用counting()作为下游收集器来统计每个组的大小。

PaperFake
PaperFake

AI写论文

下载
import javafx.collections.ObservableList;
import java.util.Map;
import java.util.stream.Collectors;

public class CountItemsStream {

    public static Map<String, Long> countByIdStream(ObservableList<CustomClass> list) {
        return list.stream()
                   .collect(Collectors.groupingBy(
                       CustomClass::getId, // 根据CustomClass对象的getId方法返回值进行分组
                       Collectors.counting() // 对每个分组中的元素进行计数
                   ));
    }

    public static void main(String[] args) {
        ObservableList<CustomClass> myCustomList = DataInitializer.initializeList();
        Map<String, Long> counts = countByIdStream(myCustomList);

        System.out.println("\nStream API方法计数结果:");
        counts.forEach((id, count) -> System.out.println("id=" + id + ", count=" + count));
        // 预期输出与迭代方法相同:
        // id=1, count=4
        // id=2, count=2
        // id=3, count=1
    }
}

代码解析:

  • list.stream():将ObservableList转换为一个Stream<CustomClass>。
  • .collect(Collectors.groupingBy(classifier, downstreamCollector)):这是Stream API中用于分组和聚合的核心方法。
    • CustomClass::getId:这是一个方法引用,作为classifier(分类器)。它告诉groupingBy如何从每个CustomClass对象中提取用于分组的键(即id)。groupingBy会根据这个键将所有具有相同id的对象收集到一个列表中。
    • Collectors.counting():这是downstreamCollector(下游收集器)。它应用于每个分组后的列表,对列表中的元素进行计数,并返回一个Long类型的结果。 最终,collect方法会返回一个Map<String, Long>,其中键是id,值是该id出现的总次数。

Stream API的优势:

  • 简洁性: 代码更紧凑,意图更明确。
  • 可读性: 对于熟悉函数式编程的开发者来说,其流程更易于理解。
  • 并行化: Stream API可以很容易地通过.parallelStream()实现并行处理,对于大规模数据集可以提升性能。

4. 结果展示与注意事项

无论采用哪种方法,最终都会得到一个Map,其中键是id,值是对应的计数。我们可以通过遍历这个Map来打印或进一步处理结果。

// 假设 counts 是通过上述任一方法获得的 Map<String, Integer> 或 Map<String, Long>
public static void printCounts(Map<String, ? extends Number> counts) {
    System.out.println("最终统计结果:");
    counts.forEach((id, count) -> {
        System.out.println("id=" + id + ", count=" + count);
    });
}

// 示例调用
// Map<String, Integer> iterativeCounts = CountItemsIterative.countByIdIterative(DataInitializer.initializeList());
// printCounts(iterativeCounts);

// Map<String, Long> streamCounts = CountItemsStream.countByIdStream(DataInitializer.initializeList());
// printCounts(streamCounts);

注意事项:

  1. JavaFX无关性: 值得注意的是,本文讨论的计数逻辑是纯粹的Java集合操作,与JavaFX的UI组件或生命周期本身并无直接关联。ObservableList在此处仅仅作为一个普通的List来使用。如果你需要在UI中实时显示这些计数并响应列表变化,那么可能需要进一步结合JavaFX的绑定和监听机制。
  2. 性能考量: 对于小型到中型数据集,迭代方法和Stream API方法的性能差异通常可以忽略不计。但对于非常大的数据集,Stream API在并行处理方面的潜力可能会带来显著的性能优势。
  3. 可读性与团队熟悉度: 选择哪种方法也应考虑团队对Java 8 Stream API的熟悉程度。传统迭代方法对于所有Java开发者都易于理解,而Stream API可能需要一定的学习曲线。
  4. 自定义类的equals()和hashCode(): 如果你的计数逻辑不仅仅是基于单个属性(如id),而是基于整个CustomClass对象的相等性,那么务必在CustomClass中正确重写equals()和hashCode()方法。然而,对于本教程中基于特定属性id的计数,则无需重写这两个方法。

总结

本教程详细展示了如何在Java中,特别是处理ObservableList<CustomClass>时,统计自定义对象中特定属性的出现次数。我们探讨了两种主要方法:

  1. 传统迭代方法:利用HashMap手动遍历列表,根据id进行增量计数。这种方法直观易懂,适用于各种场景。
  2. Java Stream API方法:利用stream().collect(Collectors.groupingBy(classifier, downstreamCollector)),以更声明式和简洁的方式实现分组和计数。这种方法在代码简洁性和处理大规模数据时的并行化潜力方面具有优势。

根据你的项目需求、团队熟悉度以及性能要求,可以选择最适合的方法来实现你的计数逻辑。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1031

2023.08.02

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

77

2025.09.05

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

40

2025.11.16

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

67

2025.11.17

java判断map相关教程
java判断map相关教程

本专题整合了java判断map相关教程,阅读专题下面的文章了解更多详细内容。

47

2025.11.27

数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

389

2023.06.29

如何删除数据库
如何删除数据库

删除数据库是指在MySQL中完全移除一个数据库及其所包含的所有数据和结构,作用包括:1、释放存储空间;2、确保数据的安全性;3、提高数据库的整体性能,加速查询和操作的执行速度。尽管删除数据库具有一些好处,但在执行任何删除操作之前,务必谨慎操作,并备份重要的数据。删除数据库将永久性地删除所有相关数据和结构,无法回滚。

2111

2023.08.14

vb怎么连接数据库
vb怎么连接数据库

在VB中,连接数据库通常使用ADO(ActiveX 数据对象)或 DAO(Data Access Objects)这两个技术来实现:1、引入ADO库;2、创建ADO连接对象;3、配置连接字符串;4、打开连接;5、执行SQL语句;6、处理查询结果;7、关闭连接即可。

357

2023.08.31

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.4万人学习

C# 教程
C# 教程

共94课时 | 11.3万人学习

Java 教程
Java 教程

共578课时 | 81.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号