过滤LinkedList的优选方法

时间:2015-01-20 16:00:59

标签: java

类TestListRemoveFunctional& TestListRemoveUpdateState在LinkedList的运行时执行过滤。

我认为TestListRemoveFunctional实现更清晰,因为它不更新状态,但效率较低,因为它在每个过滤步骤创建一个新List。

虽然TestListRemoveFunctional& TestListRemoveUpdateState本质上执行相同的工作,TestListRemoveFunctional是优选的,因为它不更新状态,不像TestListRemoveUpdateState中的过滤实现。

请注意我仅限于不使用java8 lambdas或项目Guava lambdas。

可以确认我的断言TestListRemoveFunctional更可取吗?

import java.util.LinkedList;

public class TestListRemoveFunctional {

    public static void main(String args[]) {

        TestListRemoveFunctional t = new TestListRemoveFunctional();
        LinkedList<MyObj> l = new LinkedList<MyObj>();
        l.add(new MyObj("1"));
        l.add(new MyObj("2"));

        System.out.println("size : "+l.size());

        LinkedList<MyObj> f1 = t.filterItem1(l);
        System.out.println("size : "+f1.size());

        LinkedList<MyObj> f2 = t.filterItem2(f1);
        System.out.println("size : "+f2.size());
    }

    private LinkedList<MyObj> filterItem1(LinkedList<MyObj> l) {

        LinkedList<MyObj> toReturn = new LinkedList<MyObj>();
        for (MyObj myObj : l) {

            if (!myObj.param.equalsIgnoreCase("1")) {
                toReturn.add(myObj);
            }
        }
        return toReturn;
    }

    private LinkedList<MyObj> filterItem2(LinkedList<MyObj> l) {

        LinkedList<MyObj> toReturn = new LinkedList<MyObj>();
        for (MyObj myObj : l) {

            if (!myObj.param.equalsIgnoreCase("2")) {
                System.out.println(myObj.param);
                toReturn.add(myObj);
            }
        }
        return toReturn;
    }



    private static class MyObj {

        public String param;

        public MyObj(String param) {
            this.param = param;
        }
    }

}

********************************************************************************************


import java.util.Iterator;
import java.util.LinkedList;

public class TestListRemoveUpdateState {

    public static void main(String args[]) {

        TestListRemoveUpdateState t = new TestListRemoveUpdateState();
        LinkedList<MyObj> l = new LinkedList<MyObj>();
        l.add(new MyObj("1"));
        l.add(new MyObj("2"));

        System.out.println("size is : " + l.size());

        t.filterItem1(l);       
        System.out.println("size is : " + l.size());

        t.filterItem2(l);   
        System.out.println("size is : " + l.size());
    }

    private void filterItem1(LinkedList<MyObj> l) {

        Iterator<MyObj> iter = l.iterator();
        while (iter.hasNext()) {
            MyObj myObj = iter.next();

            if (myObj.param.equalsIgnoreCase("1")) {
                iter.remove();
            }
        }
    }

    private void filterItem2(LinkedList<MyObj> l) {

        Iterator<MyObj> iter = l.iterator();
        while (iter.hasNext()) {
            MyObj myObj = iter.next();

            if (myObj.param.equalsIgnoreCase("2")) {
                iter.remove();
            }
        }
    }

    private static class MyObj {

        public String param;

        public MyObj(String param) {
            this.param = param;
        }
    }

}

3 个答案:

答案 0 :(得分:2)

什么更好?保持原始项目的状态或效率?为了证明在这些课程之间做出任何选择,你必须说出你认为最重要的特质,因为你没有一个没有另一个。 顺便说一句,两者都有一些缺陷,无论是效率还是可读性

更新

(可读性)而不是两种用于过滤的方法(一个用于项目1,一个用于项目2),仅需要一种方法:列表&lt; T&gt; filterItem(List&lt; T&gt; l,T item)

(可重用性)使用泛型而不是特定类型。而不是&lt; MyObj&gt;,而是将它们声明为&lt; T&gt;。这样,您可以将这些类和方法与任何组件的列表一起使用。

如果将参数声明为List而不是LinkedList,则可以增加这些方法的可用性。

(灵活性)如果将返回类型声明为List,则可以更改要使用的List的特定实现,同时避免类的用户必须重新编写代码。

使用像commons-collections

这样的“过滤器”类会更好

(效率)在你使用equalsIgnoreCase的过滤器方法的特定实现中,字符串不区分大小写,在这种情况下你可以使用equals。

(安全)列表可以包含null,具体取决于实现。特别是,LinkedList可以,因此通过访问列表的元素以及访问MyObj.param的值时,在这些过滤器中存在NullPointerException的风险。

答案 1 :(得分:1)

这取决于你的意思&#34;更喜欢&#34;。通过使用迭代器(正如您所做的那样),可以在迭代过程中从列表中删除元素。

如果你看看你的其他方法,那么是的,你正在创建一个新的链表。在最糟糕的情况下,如果您最终没有过滤任何内容,最终会使用O(2*n)空格。所以这取决于你是否习惯使用更多的内存。

我认为第一种方法很好,因为根据文档,使用iterator.remove()是非常安全的。如果您不能保证其他人同时修改该集合(即并发访问),那将是不安全的。

答案 2 :(得分:0)

链表的一个优点是可以进行非常有效的remove操作。

让我们考虑以下链表(在java中,链表实际上是双向链表):

e1 <-> e2 <-> e3 <-> e4 <-> e5

如果您要删除e3,您只需要:

e3.previous.next = e3.next;
e3.next.previous = e3.previous;
e3.next = null;
e3.previous = null;
e3.element = null;

这正是iterator.remove()的作用。

因此,TestListRemoveUpdateState效率更高,因为您正在处理LinkedList


作为旁注,ArrayList上的首选方法是TestListRemoveFunctional

如果要对ArrayList进行过滤,那么TestListRemoveFunctionalTestListRemoveUpdateState更有效,因为ArrayList上的删除操作每次都会重新创建一个完整的后备数组被调用(即使System.arrayCopy 非常有效)。