考虑这段代码:
public void doSearch(ActionEvent event) {
String query = searchTextField.getText();
if (query.isEmpty()) {
data = FXCollections.observableArrayList(dc.getJobCoachRepo().getList());
usersTableView.setItems(data);
} else {
String searchOn = "search" + searchChoiceBox.getValue();
try {
Method m = this.getClass().getMethod(searchOn, String.class);
m.invoke(this, query);
} catch (Exception e) {
}
}
}
public void searchFirstName(String query) {
data = FXCollections.observableArrayList(dc.getJobCoachRepo().searchFirstName(query));
usersTableView.setItems(data);
}
...
...
我在这里使用 java 反射来避免 if 构造。选择框用于让用户决定他要搜索什么属性,目前有 6 种可能性。我从其他学生那里得到了一些评论,认为使用反思是“不好的做法”。是这样吗?为什么?
这是不好的做法有很多原因。其中:
考虑使用
Consumer<String>
对象填充组合框:
ComboBox<Consumer<String>> searchChoiceBox = new ComboBox<>();
searchChoiceBox.getItems().add(createSearchOption(this::searchFirstName, "First Name"));
// ...
private Consumer<String> createSearchOption(Consumer<String> search, String name) {
return new Consumer<String>() {
@Override
public void accept(String s) {
search.accept(s);
}
@Override
public String toString() {
return name ;
}
};
}
然后你就可以:
public void doSearch(ActionEvent event) {
String query = searchTextField.getText();
if (query.isEmpty()) {
data = FXCollections.observableArrayList(dc.getJobCoachRepo().getList());
usersTableView.setItems(data);
} else {
searchChoiceBox.getValue().accept(query);
}
}
是的,反射很慢,并且以这种方式使用时会创建脆弱的代码。
如果你想避免if语句,你应该使用多态性。使用
Searcher
创建接口 public void search(String query)
,为您想要执行的每种类型的搜索创建实现,然后将每个实现的实例作为 Map<String, Searcher>
的值,并以搜索选择框的值作为键控。
因为 Java 枚举是对象,所以您也可以使用枚举作为映射。每个枚举值都会定义自己的
search(string)
实现。然后您可以使用 SearchEnumTypeName.valueOf(searchChoiceBox.getValue()).search(query)
调用您想要的实现
如果您对 GraalVM 的提前编译 感兴趣(微服务领域越来越感兴趣),我可以告诉您反射是最大的障碍。我认为这是没有必要的。
您必须手动识别 Java 链接器必须保留的类(通过 Reflection.json),因为它试图减少使二进制文件膨胀的未使用代码。
直接回答问题:
Java 反射是不好的做法吗?
不。这是语言的一个特性,在某些情况下是必要的。在非常高的层面上,它是单独编译的代码库之间开发人员 API 的有效形式。换句话说,如果您包含第三方代码,则该代码公开的对象可能不会公开任何其他用于访问有关传入数据的详细信息的 API。这要求您使用库和反射,或者避免图书馆。选择前者并不是“不好的做法”。
PS:如果不清楚,很乐意提供代码片段