Java 如何从列表中筛选元素
我正在尝试实现一个相当简单的方法,在这个方法中我想要过滤一个列表。这是一个文件对象列表,应该只有一个文件以.asp结尾-我希望从列表中排除该文件。请记住,我实际上并不想从列表中删除此文件,我只是希望能够在该列表的特定迭代中忽略它 我最初的(暴力)实现如下所示:Java 如何从列表中筛选元素,java,guava,Java,Guava,我正在尝试实现一个相当简单的方法,在这个方法中我想要过滤一个列表。这是一个文件对象列表,应该只有一个文件以.asp结尾-我希望从列表中排除该文件。请记住,我实际上并不想从列表中删除此文件,我只是希望能够在该列表的特定迭代中忽略它 我最初的(暴力)实现如下所示: public List<File> getSurveyFiles() throws Exception { List<File> surveyFiles = new ArrayList<File>
public List<File> getSurveyFiles() throws Exception {
List<File> surveyFiles = new ArrayList<File>(files.size() - 1);
for ( File f : files ) {
if ( !f.getName().endsWith(".asp") ) {
surveyFiles.add(f);
}
}
return surveyFiles;
}
public class SurveyFileControllerPredicate implements Predicate<File> {
@Override
public boolean apply(File file) {
return file.getName().endsWith(".asp");
}
}
...
public Iterable<File> getSurveyFiles() throws Exception {
return Iterables.filter(
files,
Predicates.not(new SurveyFileControllerPredicate())
);
}
public abstract class IteratorFilter<E> implements Iterator<E> {
private final Iterator<E> iterator;
private E next = null;
public IteratorFilter(Iterator<E> iterator) {
this.iterator = iterator;
}
@Override
public boolean hasNext() {
if (next!=null) return true;
while (iterator.hasNext()) {
next = iterator.next();
if (keep(next)) return true;
}
return false;
}
@Override
public E next() {
if (next==null)
do next = iterator.next(); while (!keep(next));
E result = next;
next = null;
return result;
}
@Override
public void remove() {
iterator.remove(); // Specs require: throw new UnsupportedOperationException();
}
protected abstract boolean keep(E item);
}
public List getSurveyFiles()引发异常{
List surveyFiles=new ArrayList(files.size()-1);
用于(文件f:文件){
如果(!f.getName().endsWith(“.asp”)){
调查文件。添加(f);
}
}
返回调查文件;
}
它是有效的,但我正在创建第二个列表,并且从一个列表复制到另一个列表,这让我觉得非常浪费
我曾经玩弄过的另一个选择是使用番石榴库(http://code.google.com/p/guava-libraries/)并利用其过滤功能,如下所示:
public List<File> getSurveyFiles() throws Exception {
List<File> surveyFiles = new ArrayList<File>(files.size() - 1);
for ( File f : files ) {
if ( !f.getName().endsWith(".asp") ) {
surveyFiles.add(f);
}
}
return surveyFiles;
}
public class SurveyFileControllerPredicate implements Predicate<File> {
@Override
public boolean apply(File file) {
return file.getName().endsWith(".asp");
}
}
...
public Iterable<File> getSurveyFiles() throws Exception {
return Iterables.filter(
files,
Predicates.not(new SurveyFileControllerPredicate())
);
}
public abstract class IteratorFilter<E> implements Iterator<E> {
private final Iterator<E> iterator;
private E next = null;
public IteratorFilter(Iterator<E> iterator) {
this.iterator = iterator;
}
@Override
public boolean hasNext() {
if (next!=null) return true;
while (iterator.hasNext()) {
next = iterator.next();
if (keep(next)) return true;
}
return false;
}
@Override
public E next() {
if (next==null)
do next = iterator.next(); while (!keep(next));
E result = next;
next = null;
return result;
}
@Override
public void remove() {
iterator.remove(); // Specs require: throw new UnsupportedOperationException();
}
protected abstract boolean keep(E item);
}
公共类SurveyFileControllerPredicate实现谓词{
@凌驾
公共布尔应用(文件){
返回文件.getName().endsWith(“.asp”);
}
}
...
public Iterable getSurveyFiles()引发异常{
返回Iterables.filter(
文件夹,
谓词.not(新的SurveyFileControllerPredicate())
);
}
filter的实现在迭代时而不是提前删除.asp文件,因此这段代码的优点是不生成第二个列表,但我觉得这使我的代码更加复杂
还有其他更简单的实现我没有考虑吗
在整个方案中,我选择哪种实现可能并不重要。我只是好奇其他开发者会如何解决这个问题,以及他们会选择什么选项
谢谢。在某个时候,我为自己编写了两个非常通用的帮助器类,它们处理如下问题:
public List<File> getSurveyFiles() throws Exception {
List<File> surveyFiles = new ArrayList<File>(files.size() - 1);
for ( File f : files ) {
if ( !f.getName().endsWith(".asp") ) {
surveyFiles.add(f);
}
}
return surveyFiles;
}
public class SurveyFileControllerPredicate implements Predicate<File> {
@Override
public boolean apply(File file) {
return file.getName().endsWith(".asp");
}
}
...
public Iterable<File> getSurveyFiles() throws Exception {
return Iterables.filter(
files,
Predicates.not(new SurveyFileControllerPredicate())
);
}
public abstract class IteratorFilter<E> implements Iterator<E> {
private final Iterator<E> iterator;
private E next = null;
public IteratorFilter(Iterator<E> iterator) {
this.iterator = iterator;
}
@Override
public boolean hasNext() {
if (next!=null) return true;
while (iterator.hasNext()) {
next = iterator.next();
if (keep(next)) return true;
}
return false;
}
@Override
public E next() {
if (next==null)
do next = iterator.next(); while (!keep(next));
E result = next;
next = null;
return result;
}
@Override
public void remove() {
iterator.remove(); // Specs require: throw new UnsupportedOperationException();
}
protected abstract boolean keep(E item);
}
公共抽象类迭代器过滤器实现迭代器{
私有最终迭代器;
private next=null;
公共迭代器过滤器(迭代器迭代器){
this.iterator=迭代器;
}
@凌驾
公共布尔hasNext(){
if(next!=null)返回true;
while(iterator.hasNext()){
next=迭代器.next();
if(keep(next))返回true;
}
返回false;
}
@凌驾
公共教育{
if(next==null)
do next=iterator.next();而(!keep(next));
E结果=下一个;
next=null;
返回结果;
}
@凌驾
公共空间删除(){
迭代器.remove();//规范要求:抛出新的UnsupportedOperationException();
}
受保护抽象布尔保留(E项);
}
以及:
公共抽象类IterableFilter实现Iterable{
私人终审法院;
公共Iterable过滤器(Iterable-Iterable){
this.iterable=iterable;
}
@凌驾
公共迭代器迭代器(){
返回新的IteratorFilter(iterable.iterator()){
@凌驾
受保护布尔保持(T项){
返回IterableFilter.this.keep(项目);
}
};
}
保护抽象布尔保留(T项);
}
有了这些,您可以简单地执行以下操作:
public Iterable<File> getSurveyFiles() {
return new IterableFilter<File>(files) {
@Override
protected boolean keep(File item) {
return !item.getName().endsWith(".asp");
}
};
}
public Iterable getSurveyFiles(){
返回新的IterableFilter(文件){
@凌驾
受保护的布尔保留(文件项){
return!item.getName().endsWith(“.asp”);
}
};
}
它本质上与Guava谓词方法相同,只是不需要跟踪谓词对象,也不引入新的库依赖项。您可以使用
toString()函数组合一个正则表达式匹配谓词:
public Iterable<File> getSurveyFiles() {
return Iterables.filter(files, Predicates.compose(
Predicates.not(Predicates.containsPattern("\\.asp$")),
Functions.toStringFunction()));
}
public Iterable getSurveyFiles(){
返回Iterables.filter(文件、谓词.compose(
谓词.not(谓词.containsPattern(“\\.asp$”),
Functions.toString函数());
}
如果您愿意在迭代站点编写过滤(而不是编写返回过滤后的副本或视图的函数),Java 8 streams可以使这一点非常简单:
files.stream().filter(f -> !f.getName().endsWith(".asp")).forEachOrdered(f -> {
//process file f
});
如果只在少数位置执行此筛选,则这比编写返回筛选副本或视图的方法更简洁,并使筛选操作靠近使用筛选列表的位置。如果您在许多地方执行此筛选,并且以后可能希望以不同的方式筛选列表,那么编写一个方法可能会更好,但它可以是一个返回流的方法:
public Stream<File> getSurveyFiles() {
return files.stream().filter(f -> !f.getName().endsWith(".asp"));
}
公共流getSurveyFiles(){
返回文件.stream().filter(f->!f.getName().endsWith(“.asp”);
}
然后,您可以对返回值调用forEachOrdered
。如果需要非流操作,请调用iterator
以获取迭代器或.collect(Collectors.toList())
以获取列表的筛选副本。是否在适当的上下文中迭代文件?是否可以在填充原始列表本身时添加筛选器?我的意思是,原始列表填充是通过您的代码完成的,或者您正在接收预填充的列表?您也不需要使用Guava跟踪谓词对象。顺便说一句,remove()
不应该在过滤的迭代器上受支持:在调用hasNext()
之后,remove()
将不再像指定的那样删除上次调用next()
返回的对象。它甚至可以删除迭代器不“包含”的元素(迭代器跳过了该元素)。@ColinD完全同意。实际上,我在考虑hasNext()->remove()场景,但决定让我的代码保持我使用它的方式,因为(至少在我的例子中)我从未遇到过这样的情况:我删除了一个我没有首先使用next()检查的对象。但是我在代码中添加了一条注释,因为您完全正确。@ColinD:为了完整起见,您认为使用两个并行运行的迭代器可以使remove()方法正常工作吗