Java集合操作

线程安全

在Java里,线程安全一般体现在两个方面:

1、多个thread对同一个java实例的访问(read和modify)不会相互干扰,它主要体现在关键字synchronized.如ArrayList和Vector,HashMap和Hashtable(后者每个方法前都有synchronized关键字)。如果你在interator一个List对象时,其它线程remove一个element,问题就出现了。

2、每个线程都有自己的字段,而不会在多个线程之间共享。它主要体现在java.lang.ThreadLocal类,而没有Java关键字支持,如像static、transient那样。

Java集合操作_第1张图片

一、List集合

1、得到list里的数据

  @Test
    public void testGetData() {
        List<String> list = new ArrayList<String>();
        list.add("aa");
        list.add("bb");
        list.add("cc");

        //1、通过下标得到数据
        System.out.println(list.get(0));

        //2、通过for循环得到数据,最常用
        for (String str : list) {
            System.out.println(str);
        }

        //3、通过iterator,不建议使用
        Iterator<String> it = list.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
    }


2、subList
     JDK中,List接口有一个实例方法List<E> subList(int fromIndex, int toIndex),
     其作用是返回一个以fromIndex为起始索引(包含),以toIndex为终止索引(不包含!!!)的子列表(List)。
     但值得注意的是,返回的这个子列表的幕后其实还是原列表; 也就是说,修改这个子列表,将导致原列表也发生改变;反之亦然。

    @Test
    public void subList() {
        ArrayList<Integer> originalList = new ArrayList<Integer>();

        for (int i = 0; i < 5; i++) {
            originalList.add(i); // auto boxing
        }

        // 一开始的list数据
        System.out.print("the original list: ");
        for (Integer num : originalList) {
            System.out.print(num + " "); // 0 1 2 3 4
        }
        System.out.println();

        // 用subList后的list 1 2 3!!!
        List<Integer> subList = originalList.subList(1, 4);
        // 移除2
        subList.remove(1);

        System.out.print("sub list: ");
        for (Integer num : subList) {
            System.out.print(num + " "); // 1 3
        }
        System.out.println();

        // 一开始的list数据
        System.out.print("the original list after subList modified: ");
        for (Integer num : originalList) {
            System.out.print(num + " "); // 0 1 3 4
        }

    }

3、list排序

先创建一个对象

public class User implements Comparable<User>{
    private String name;
    private Integer order;
    private double money;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getOrder() {
        return order;
    }

    public void setOrder(Integer order) {
        this.order = order;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }
    @Override
    public int compareTo(User user) {
        //比较的参数需是对象
        return this.getOrder().compareTo(user.getOrder());
    }

//    //降序
//    @Override
//    public int compareTo(User user) {
//        if (user.getMoney() < this.getMoney()) {
//            return -1;
//        } else if (user.getMoney() == this.getMoney()) {
//            return 0;
//        } else {
//            return 1;
//        }
//    }
}

1、用Collections.sort方法对list排序有两种方法
     第一种是list中在对象里实现Comparable接口,重写compareTo方法,如下:

    @Test
    public void testSort1() {
        User user1 = new User();
        user1.setName("a");
        user1.setOrder(1);

        User user2 = new User();
        user2.setName("b");
        user2.setOrder(2);

        List<User> list = new ArrayList<User>();
        list.add(user2);
        list.add(user1);

        Collections.sort(list);
        for (User u : list){
            System.out.println("test1: "+u.getName());//输出结果如下a b
        }
    }
2、第二种方法是根据Collections.sort重载方法来实现,类中就定义简单的属性就行,例如:
     第一种方式代码结构简单,但是只能根据固定的属性排序,后者灵活,可以临时指定排序项,但是代码不够简洁

    @Test
    public void testSort2() {
        User user1 = new User();
        user1.setName("a");
        user1.setOrder(1);

        User user2 = new User();
        user2.setName("b");
        user2.setOrder(2);

        List<User> list = new ArrayList<User>();
        list.add(user2);
        list.add(user1);

        //根据order对User排序
        Collections.sort(list, new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                return o1.getOrder().compareTo(o2.getOrder());
            }
        });

        for (User u : list){
            System.out.println("test1: "+u.getName());//输出结果如下a b
        }
    }


二、Map集合

map是键值对的集合接口,它的实现类主要包括:HashMap,TreeMap,Hashtable以及LinkedHashMap等。其中这四者的区别如下(简单介绍):

HashMap:基于哈希表实现,它根据key的HashCode 值来存储数据,根据key可以直接获取它的Value,同时它具有很快的访问速度。HashMap最多只允许一条记录的key值为Null(多条会覆盖);允许多条记录的Value为 Null。非同步的(非线程安全)

TreeMap: 基于红黑树实现。TreeMap没有调优选项,因为该树总处于平衡状态。能够把它保存的记录根据key排序,默认是按升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。TreeMap不允许key的值为null。非同步的(非线程安全)

Hashtable: 与 HashMap类似,不同的是:key和value的值均不允许为null;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtale在写入时会比较慢。

LinkedHashMap: 保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.在遍历的时候会比HashMap慢。key和value均允许为空,非同步的(非线程安全)

1、四种Map

    @Test
    public void testMap() {
        System.out.println("*************************HashMap*************");
        Map<String, String> hashMap = new HashMap<String, String>();
        hashMap.put("d", "apple");
        hashMap.put("a", "banana");
        hashMap.put("c", "pear");
        hashMap.put("b", "orange");

        for (String key : hashMap.keySet()) {
            System.out.println(key + "=" + hashMap.get(key)); //d=apple b=orange c=pear a=banana
        }

        System.out.println("*************************Hashtable*************");
        //hashTable: 与 HashMap类似,不同的是:key和value的值均不允许为null
        Map<String, String> hashTable = new Hashtable<String, String>();
        hashTable.put("d", "apple");
        hashTable.put("a", "banana");
        hashTable.put("c", "pear");
        hashTable.put("b", "orange");

        for (String key : hashTable.keySet()) {
            System.out.println(key + "=" + hashTable.get(key)); //b=orange a=banana d=apple c=pea
        }

        System.out.println("*************************LinkedHashMap*************");
        //LinkedHashMap是HashMap的一个子类,它保留插入的顺序
        Map<String, String> linkedHashMap = new LinkedHashMap<String, String>();
        linkedHashMap.put("d", "apple");
        linkedHashMap.put("a", "banana");
        linkedHashMap.put("c", "pear");
        linkedHashMap.put("b", "orange");
        for (String key : linkedHashMap.keySet()) {
            System.out.println(key + "=" + linkedHashMap.get(key)); //按顺序输出d=apple a=banana c=pear b=orange

        }

        System.out.println("*************************TreeMap*************");
        //TreeMap: 根据key排序,默认是按升序排序
        Map<String, String> treeMap = new TreeMap<String, String>();
        treeMap.put("d", "apple");
        treeMap.put("a", "banana");
        treeMap.put("c", "pear");
        treeMap.put("b", "orange");

        for (String key : treeMap.keySet()) {
            System.out.println(key + "=" + treeMap.get(key)); //a=banana b=orange c=pear d=apple
        }

    }


2、map遍历

map有三种可能的视图

所有 键值对 参见 entrySet() 返回 Map 中所包含映射的 Set 视图。 Set 中的每个元素都是一个 Map.Entry 对象,可以使用 getKey() 和 getValue() 方法(还有一个 setValue() 方法)访问后者的键元素和值元素
所有键 参见 keySet() 返回 Map 中所包含键的 Set 视图。 删除 Set 中的元素还将删除 Map 中相应的映射(键和值)
所有值 参见 values() 返回 map 中所包含值的 Collection 视图。 删除 Collection 中的元素还将删除 Map 中相应的映射(键和值)


    @Test
    public void testTraverseMap() {
        Map<String, String> map = new HashMap<String, String>();
        map.put("1", "value1");
        map.put("2", "value2");
        map.put("3", "value3");

        //第一种:普遍使用,二次取值
        System.out.println("通过Map.keySet遍历到的是key,通过key获取value: ");
        for (String key : map.keySet()) {
            System.out.println("key= " + key + " and value= " + map.get(key));
        }

        //第二种:推荐,尤其是容量大时
        System.out.println("通过Map.entrySet遍历key和value");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
        }

        //第三种
        System.out.println("通过Map.entrySet使用iterator遍历key和value: ");
        Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, String> entry = it.next();
            System.out.println("key= " + entry.getKey() + "and value= " + entry.getValue());
        }

        //第四种
        System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
        for (String v : map.values()) {
            System.out.println("value= " + v);
        }
    }

3、Set集合

set集合不允许包含相同的元素(唯一性);判断两个对象是否相同是根据equals()方法,而不是==,返回true

1、HashSet类不是同步的(不是线程安全的)
     Java.util.HashSet类实现了Java.util.Set接口。
     * l.1  它不允许出现重复元素;
     * l.2  根据hashCode()值来存放元素,所以不保证集合中元素的排列顺序
     * l.3  允许包含值为null的元素,但最多只能有一个null元素。
     * 1.4.如果两个对象通过equals()方法返回true,这两个对象的hashCode值也相同

    @Test
    public void testHashSet() {
        Set<java.io.Serializable> h = new HashSet<java.io.Serializable>();

        h.add("1st");
        h.add("2nd");
        h.add(3);
        h.add(4.0);
        h.add("2nd");            //重复元素,未被添加
        h.add(3);      //重复元素,未被添加
        h.add(new Date());

        System.out.println("开始:size=" + h.size());//5

        for (Serializable o : h) {
            System.out.println(o); //2nd 3 1st 4.0 时间
        }

        h.remove("2nd");
        System.out.println("移除元素后:size=" + h.size()); //
        System.out.println(h);
    }
2、TreeSet描述的是Set的一种变体——可以实现排序等功能的集合,
     它在讲对象元素添加到集合中时会自动按照某种比较规则将其插入到有序的对象序列中,
      并保证该集合元素组成的读uixiangxulie时刻按照“升序”排列。

    @Test
    public void testTreeSet() {
        Set<String> ts = new TreeSet<String>();
        ts.add("orange");
        ts.add("apple");
        ts.add("banana");
        ts.add("grape");

        for (String fruit : ts) {
            System.out.print(fruit + " ");//apple banana grape orange 
        }
    }



















你可能感兴趣的:(java,list,map,set)