【发布时间】:2021-11-07 21:51:42
【问题描述】:
简介
你好,
我正在开发一个使用多个双向哈希映射和可观察列表的 Java 应用程序。我的代码有效,但我遇到了一个我似乎无法摆脱的奇怪怪癖。我在网上找不到任何关于此的信息,所以我想我会分享它,看看有没有其他人以前见过。
当代码第一次打开时,有一个方法可以查询 MySQL 数据库并提取作者列表(该程序是一个库数据库应用程序)的姓名,这些作者的姓名被分成不同的部分;名字、中间名和姓氏。然后这个方法会遍历缓存的行集并将它们组合在一起,然后将它们添加到我之前提到的双向哈希映射和可观察列表中。然后在整个代码中将这些用于各种目的。
在初始创建后刷新列表的任何时候都会出现此问题。 程序运行时,会不时对数据库进行新查询并刷新列表以确保可获得最新信息。第一次运行该方法时,它会执行我提到的所有这些步骤,大约需要 8 毫秒才能完成。但是当进行刷新时,该时间会跳到大约 1,400 毫秒。值得注意的是,刷新次数越多,时间就越长。 显然,这是一个主要的时间高峰,但我看不到代码中的任何内容来表明导致这种情况的原因。我将解释我如何确定它是下面的可观察列表...
我在下面链接了一张图片,以展示我所说的示例。 请注意,正在处理的作者数量是相同的。其他打印输出是我同时测试的附加信息,与这篇文章无关。
这是方法的代码。
public void createAuthorHashMap() 抛出异常 { 字符串 authorFirstName、authorMiddleName、authorLastName、authorFullName; 整数ID;
// Get the Cached Row Set for all Authors in the database
CachedRowSet authorList = connectionCommands.readDatabase(sqlCommands.selectAllAuthor);
// Reset the contents of the hashmap and observable list
bookAttributes.bidiMapAuthors.clear();
bookAttributes.listAuthors.clear();
choiceBoxAuthor.setItems(null);
// Combine the sperate parts of the names from the cached rowset
while (authorList.next()) {
ID = authorList.getInt(1);
authorFirstName = authorList.getString(2);
authorMiddleName = authorList.getString(3);
authorLastName = authorList.getString(4);
if (authorMiddleName == null) {
authorFullName = (authorFirstName + " " + authorLastName);
} else {
authorFullName = (authorFirstName + " " + authorMiddleName + " " + authorLastName);
}
// Add the authors to the hashmap and list
bookAttributes.bidiMapAuthors.put(ID, authorFullName);
bookAttributes.authors.add(authorFullName);
}
// Add the list to the choiceBox and auto-complete textfield
choiceBoxAuthor.setItems(bookAttributes.authors);
TextFields.bindAutoCompletion(textFieldAuthor, bookAttributes.listAuthors);
}
这是 hashmap 和 Observable 列表的代码。
// Lists
public static ObservableList<String> FictionGenres = FXCollections.observableArrayList();
public static ObservableList<String> NonFictionGenres = FXCollections.observableArrayList();
public static ObservableList<String> blankList=FXCollections.observableArrayList();
public static ObservableList<String> authors = FXCollections.observableArrayList();
public static ObservableList<String> publishers = FXCollections.observableArrayList();
public static ObservableList<String> languages = FXCollections.observableArrayList();
public static ObservableList<String> series = FXCollections.observableArrayList();
// Hashmaps
public static BidiMap<Integer, String> bidiMapAuthors = new TreeBidiMap<>();
public static BidiMap<Integer, String> bidiMapPublishers = new TreeBidiMap<>();
public static BidiMap<Integer, String> bidiMapFictionGenres = new TreeBidiMap<>();
public static BidiMap<Integer, String> bidiMapNonFictionGenres = new TreeBidiMap<>();
public static BidiMap<Integer, String> bidiMapLanguages = new TreeBidiMap<>();
public static BidiMap<Integer, String> bidiMapSeries = new TreeBidiMap<>();
重要的一点是,哈希映射和列表是创建并存储在一个单独的类中,以便在程序运行期间可以跨多个控制器访问它们。
代码本身并不复杂,并且相当容易理解,但是我想提请您注意的是while循环后面的两行代码。这两行将作者姓名添加到哈希映射和列表中。
bookAttributes.bidiMapAuthors.put(ID, authorFullName);
bookAttributes.authors.add(authorFullName);
测试
我的测试就是这样进行的。我在方法的不同部分放置了计时器,并多次运行它并将减速的原因缩小到我之前提到的两行代码。应该注意的是我得到的时间该方法的所有其他部分都完全符合我的预期。
然后我注释掉了将名称添加到哈希映射的行并且问题仍然存在,但是一旦我将其反转并注释掉将名称添加到列表中的行然后问题立即消失并且从未出现无论我运行该方法多少次都返回。
bookAttributes.authors.add(authorFullName);
这里发生的事情是否有任何原因,或者是否存在我忽略的明显错误并且我只是个白痴?我很好奇,我很感激任何信息!
【问题讨论】:
-
我建议创建一个minimal reproducible example。您可以使用随机生成的数据而不是 SQL。最有可能的是,在创建它时,您可以将问题缩小到足以自己找到解决方案的范围,如果没有,它将帮助其他人快速重现它,对其进行分析/基准测试并为您提供答案。
-
问题可能是您每次都在创建新的自动完成绑定,而不是用新值更新现有的绑定(通过清除绑定并向绑定添加新建议)。请参阅stackoverflow.com/questions/45778462/update-autocomplete-javafx 的已接受答案
-
显而易见(也可能是错误的)答案是,当数据发生变化时,无论听众做什么,都会花费时间。尝试将数据放入临时列表,然后使用
ObservableList.setAll。 -
@tgdavies 我刚试过这个,它做了一点改进,但只有大约 100 毫秒。就像以前一样,这个方法第一次运行时,它几乎是立即运行的。我认为使用 setAll 方法可能会更快,但我遇到的问题仍然存在。文档也没有为我提供任何有用的信息,但我会继续尝试。
-
@tgdavies 我找到了解决方案。明天我会发布一个详细的解决方案。
标签: java performance observablelist