I want to use the strings imputed in a TextField to filter a list. I am using a KeyReleased Event on the TextField to filter the list on every key. The piece of code below filters the list when I type in a word, but when I press space and start typing another word the list gets empty. I am a bit new to streams. I don't know what I am doing wrong.
private ObservableList productList;
@FXML
private JFXTextField searchField;
@FXML
private TableView productTable;
@FXML
void searchKeyReleased(KeyEvent event) {
String searchText = searchField.getText();
List searchableWords = Arrays.asList(searchText.toLowerCase().trim().split("\\s+"));
List filteredList = searchableWords.stream()
.flatMap(i ->productList.stream()
.filter(j -> j.getPartDesc().toLowerCase().contains(i)))
.collect(Collectors.toList());
ObservableList productFilteredList = FXCollections.observableArrayList(filteredList);
productTable.setItems(productFilteredList);
}
----------
public class Products_Data {
private final StringProperty partDesc = new (this,"PartDesc",null);
public Products_Data() {}
public final StringProperty getPartDescProperty() {return partDesc;}
public final String getPartDesc(){return partDesc.get();}
public final void setPartDesc(String partDesc) {
getPartDescProperty().set(partDesc);
}
}
解决方案
I can’t see a fundamental problem in your Stream code. The way, you’ve written it, is not very efficient and it allows elements matching multiple words to occur multiple times in the result list. Perhaps, the UI you’re setting the result on can’t handle this.
I’d create a single filter out of the entered text, which will match if any of the words appears in the element, using a case insensitive matching instead of repeatedly converting every string to lowercase. E.g. with a utility method like this:
static final Pattern SPACE = Pattern.compile("\\s+");
public static Predicate getFilter(Function super T, String> f, String words) {
String regex = SPACE.splitAsStream(words)
.map(Pattern::quote).collect(Collectors.joining("|"));
Predicate sp = Pattern.compile(regex, Pattern.CASE_INSENSITIVE).asPredicate();
return t -> sp.test(f.apply(t));
}
which can be used as
List filteredList = productList.stream()
.filter(getFilter(Products_Data::getPartDesc, searchField.getText()))
.collect(Collectors.toList());