Java集合(上)

集合类和数组不一样,数组元素既可以是基本类型的值,也可以是对象; 而集合里只能保存对象。

Java的集合类主要由两个接口派生而出:Collection和Map,Collection和Map是Java集合框架的根接口,这两个接口又包含了一些子接口或实现类。

Set和List接口是Collection接口派生出的两个子接口,它们分别代表了无序集合和有序集合;Queue是Java提供的队列实现,有点类似于List。
所有的Map实现类用于保存具有映射关系的数据,Map接口有众多实现类,这些实现类在功能、用法上存在一定差异,但它们都有一个功能特征:Map保存的每项数据都是key-value对。key是不可重复的。

Collection接口

Collection接口定义了如下操作集合元素的方法。

  1. boolean add(Object o):用于向集合里添加一个元素
  2. boolean addAll(Collection c):该方法把集合c里所有元素添加到指定集合中。
  3. void clear():清楚集合里所有元素,将集合变为0。
  4. boolean contains(Object o)
  5. boolean containsAll(Collection c)
  6. boolean isEmpty()
  7. boolean remove()
  8. boolean removeAll()
  9. Iterator iterator():返回一个Iterator对象,用于遍历集合里的元素
  10. int size():该方法返回集合里的元素 Object[]
  11. boolean retainAll(Collection a):求交集

集合的遍历

Java 8为Iterable接口新增了一个forEach(Consumer action)默认方法,该方法所需参数的类型是一个函数式接口,而Iterable接口是Collection接口的父接口,因此Collection集合也可直接调用该方法。

当程序调用Iterable的forEach(Consumer action)遍历集合元素时,程序会一次将集合元素传给Consumer的accept(T t)方法(该接口中唯一的抽象方法)。正因为Consumer是函数式接口,因此可以使用Lambda表达式来遍历集合元素。

package ObjectOrient;

import java.util.ArrayList;
import java.util.Iterator;

public class CollectionEach {

    public static void main(String[] args) {
        ArrayList<Object> arrayList = new ArrayList<>();
        arrayList.add("String");
        arrayList.add("5444444");
        arrayList.addAll(arrayList);
        arrayList.forEach(obj->System.out.println(obj));//使用lambda表达式遍历集合
        arrayList.removeIf(obj->(((String)obj).length()>10));//使用Predicate操作集合,即CollectionName.removeIf();
        arrayList.forEach(obj->System.out.println(obj));
        //使用iterator遍历集合
        Iterator<Object> iterator = arrayList.iterator();
        while (iterator.hasNext()) {
            String string = (String) iterator.next();
            System.out.println(string);
            if (string.equals("String")) {
                iterator.remove();
            }
            string = "I'm a new String";
        }
        /*Iterator仅用于遍历集合,Iterator本身并不提供盛装对象的能力。如果要创建Iterator对象,则必须有一个被迭代的集合。
        Iterator提供了两个方法来迭代访问Collection集合里的元素,并可通过remove()方法来删除集合中上一次next()返回的集合元素。
        当使用Iterator对集合进行迭代时,Iterator并不是把集合元素本身传给迭代变量,而是把集合元素的值传给了迭代变量,所以修改迭代变量的值没有任何意义。
        当使用Iterator迭代访问Collection集合元素时,Collection集合里的元素不能被改变,只有通过Iterator()方法删除上一次next()方法返回的集合元素才可以;否则将会引发java.util.ConcurrentModificationException异常。*/
        //使用lambda遍历iterator
        iterator.forEachRemaining(System.out::println);
        /*foreach循环中的迭代变量也不是集合元素本身,系统只是依次把集合元素的值赋给迭代变量。
         * 同样,使用foreach循环迭代访问元素时,该集合也不能被改变,否则会引发异常。
         * 使用Predicate操作集合*/
    }
}

使用Stream操作集合

package ObjectOrient;

import java.util.stream.IntStream;

public class IntStreamTest {

    public static void main(String[] args) {
        //Builder add = IntStream.builder().add(0).add(122).add(234).add(345);
        IntStream intStream = IntStream.builder().add(0).add(122).add(234).add(345).build();
        /*最后必须有.build();*/
        int asInt = intStream.max().getAsInt();//必须有getAsInt();
        System.out.println(asInt);

    }

}

集合类

HashSet类

HashSet不是同步的,如果多个线程同时访问一个hashset并修改,则必须通过代码显式保证其同步。集合元素的值可以为null。

hashset判断两个元素相同的标准是两个对象通过equals()方法比较相等,并且两个对象的hashCode()方法返回值也相等。

两个不同的对象,重写equals方法时也应该重写hashCode方法;否则:
重写equals方法并未重写hashCode方法:此时equals返回true,但hashCode方法返回不同的HashCode值时,这将导致HashSet会把这两个对象保存在hash表的不同位置,从而使两个对象都可以添加成功,这与Set集合的规则相冲突。
并未重写equals方法但重写hashCode方法:此时hashcode相同,但equals为false,hashset试图将他们保存在同一个位置,但又不行。

TreeSet类

TreeSet是SortedSet接口的实现类,正如SortSet名字所暗示的,TreeSet集合可以保元素处于排序状态。

boolean add(E e):Adds the specified element to this set if it is not already present.
boolean addAll(Collection<? extends E> c):Adds all of the elements in the specified collection to this set.
E   ceiling(E e):Returns the least element in this set greater than or equal to the given element, or null if there is no such element.(返回下边界以上的元素)
void    clear():Removes all of the elements from this set.
Object  clone():Returns a shallow copy of this TreeSet instance.
Comparator<? super E>   comparator():Returns the comparator used to order the elements in this set, or null if this set uses the natural ordering of its elements.
boolean contains(Object o):Returns true if this set contains the specified element.
Iterator<E> descendingIterator():Returns an iterator over the elements in this set in descending order.
NavigableSet<E> descendingSet():Returns a reverse order view of the elements contained in this set.
E   first():Returns the first (lowest) element currently in this set.
E   floor(E e):Returns the greatest element in this set less than or equal to the given element, or null if there is no such element.
SortedSet<E>    headSet(E toElement)
Returns a view of the portion of this set whose elements are strictly less than toElement.
NavigableSet<E> headSet(E toElement, boolean inclusive)
Returns a view of the portion of this set whose elements are less than (or equal to, if inclusive is true) toElement.
E   higher(E e)
Returns the least element in this set strictly greater than the given element, or null if there is no such element.
boolean isEmpty()
Returns true if this set contains no elements.
Iterator<E> iterator()
Returns an iterator over the elements in this set in ascending order.
E   last()
Returns the last (highest) element currently in this set.
E   lower(E e)
Returns the greatest element in this set strictly less than the given element, or null if there is no such element.
E   pollFirst()
Retrieves and removes the first (lowest) element, or returns null if this set is empty.
E   pollLast()
Retrieves and removes the last (highest) element, or returns null if this set is empty.
boolean remove(Object o)
Removes the specified element from this set if it is present.
int size()
Returns the number of elements in this set (its cardinality).
NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive)
Returns a view of the portion of this set whose elements range from fromElement to toElement.
SortedSet<E>    subSet(E fromElement, E toElement)
Returns a view of the portion of this set whose elements range from fromElement, inclusive, to toElement, exclusive.
SortedSet<E>    tailSet(E fromElement)
Returns a view of the portion of this set whose elements are greater than or equal to fromElement.
NavigableSet<E> tailSet(E fromElement, boolean inclusive)
Returns a view of the portion of this set whose elements are greater than (or equal to, if inclusive is true) fromElement.

TreeSet是根据元素的实际大小顺序进行排序的。
TreeSet采用红黑树数据结构来存储集合元素,并且支持两种排序方法:自然排序和定制排序。

自然排序

TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间的大小关系,然后将进而元素按升序排列,这种方式就是自然排序。
Java的一些常用类已经实现了Comparable接口,并提供了比较大小的标准。

  1. BigDecimal、BigInteger即所有数值型对于的包装类
  2. Character:按字符的UNICODE值进行比较
  3. Boolean:true大于false对于的包装类
  4. String:按字符的UNICODE
  5. Date、Time:后面的时间、日期比前面的大。

当把一个对象添加到TreeSet时,该对象必须实现Comparable接口,否则程序抛出异常。

如果希望TreeSet能够正常工作,TreeSet只能添加同一种类型的对象。推荐不要修改放入HashSet和TreeSet集合元素的关键实例变量。

定制排序

TreeSet的自然排序是根据元素的大小,升序排列。如果需要实现定制排序,例如降序排序,则可以通过Comparator接口的帮助。该接口里包含一个int compare(T o1,T o2)方法,该方法用于比较o1和o2的大小:如果该方法返回正整数,表明o1 > o2;返回0,则相等,返回负整数o1< o2。

package ObjectOrient;

import java.util.Random;
import java.util.TreeSet;

class Student{
    String name;
    int age;
    String Code;

    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
        Random random = new Random();
        Code = random.nextInt(10000) + 10000 + "";
    }

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + ", Code=" + Code + "]";
    }


}

public class TreeSetTest {

    public static void main(String[] args) {
        TreeSet<Object> treeSet = new TreeSet<>((obj1,obj2)->{
            Student stu1 = (Student)obj1;
            Student stu2 = (Student)obj2;
            return stu1.age > stu2.age ? -1 : stu1.age < stu2.age ? 1 : stu1.name.length() < stu2.name.length() ? 1 : 0;
        });
        treeSet.add(new Student("Jabdk", 19));
        treeSet.add(new Student("ffdsa", 23));
        treeSet.add(new Student("edcfftt", 23));
        treeSet.add(new Student("dc", 45));
        treeSet.add(new Student("dwd", 23));
        System.out.println(treeSet);
    }

}

EnumSet类

EnumSet是一个专门为枚举类设计的集合类,EnumSet中所有元素都必须是指定枚举类的枚举值,该枚举类在创建EnumSet时显式或隐式地指定。****EnumSet的集合元素也是有序的,EnumSet以枚举值在Enum类内部的定义顺序来决定集合元素的顺序。

EnumSet在内部以位向量的形式存储,这种存储方式非常紧凑高效。因此EnumSet**对象占用内存很小**,而且运行效率很好。尤其是在进行批量操作时候,如果其参数是EnumSet集合,则该批量操作的速度也非常快。

EnumSet集合不允许加入null元素,如果试图插入null元素,将会报NullPointerException异常。如果只是判断是否包含null元素或者试图删除null元素,则不会报错,只是删除时返回false。

EnumSet类并没有暴露任何构造器来创建该类的实例,程序应该通过它的类方法来创建EnumSet对象。
比如:

  1. EnumSet allOf(Class elementType)
  2. EnumSet complement(EnumSet s)
  3. EnumSet copyOf(Collection c)
        EnumSet<Season> enumSet = EnumSet.allOf(Season.class);
        boolean add = enumSet.add(Season.Winter);

各类性能分析

HashSet的性能总是要优于TreeSet,特别是最常用的添加、查询等操作。因为TreeSet需要使用额外的红黑树算法来维护集合元素的次序。只有当需要一个排序的Set时,才需要TreeSet。

HashSet还有一个子类,LinkedHashSet,对于普通的插入、删除操作,LinkedHashSet比HashSet要略慢一点,这是由于维护链表所带来的额外开销,但是由于有链表,遍历LinkedHashSet会很快。

EnumSet是所有类中性能最好的,但它只能保存枚举类的枚举值。

Set的三个实现类HashSet、TreeSet、EnumSet都是线程不安全的。如果有多个线程同时访问Set集合,并且有超过一个线程修改了Set集合,必须手动保证该Set集合的同步性。
通常可以通过Collections的工具类synchronizedSortedSet方法来“包装”该Set集合。此操作最好在创建时进行,以防止对Set集合的意外非同步访问。

SortedSet s = Collections.synchronizedSorted(new
     TreeSet(...));

List集合

List判断两个对象相等只要通过equals()方法返回true即可。
Java 8 还为List接口添加了如下两个默认方法。

  1. void replaceAll(UnaryOperator operator):根据operator指定的计算规则重新设置List集合的所有元素。
  2. void sort(Comparator c):根据Comparator参数对List集合的元素排序。

其中sort()方法需要一个Compartor对象来控制元素排序,程序使用Lambda表达式来作为参数;而replaceAll()方法则需要一个UnaryOperator来替换所有集合元素,UnaryOperator也是一个函数式接口,因此程序也可使用Lambda表达式作为参数。

package FirstTime;

import java.util.ArrayList;
import java.util.ListIterator;

public class ListTest {

    public static void main(String[] args) {
        ArrayList<Object> arrayList = new ArrayList<>();
        arrayList.add("lkjhyyuj");
        arrayList.add("sxdcfvgbtyh");
        arrayList.add("aqa");
        arrayList.add("eftds");
        arrayList.add("ioljhtdddsaa");
        arrayList.add("dd");
        arrayList.add("rtrty");
        arrayList.sort((obj1,obj2)->((String)obj1).length()-((String)obj2).length());
        System.out.println(arrayList);
        arrayList.replaceAll(obj->((String)obj).length());
        System.out.println(arrayList);
        ListIterator<Object> listIterator = arrayList.listIterator();
        listIterator.add("-------");//listIterator可以向List集合中添加元素,而iterator不可以
        listIterator.forEachRemaining(System.out::println);
    }

}

listIterator增加了向前迭代的功能:boolean hasprevious();Object previous();
ArrayList是线程不安全的;虽然vector是线程安全的,但不推荐。(stack是基于vector的,也不推荐,推荐用ArrayDeque)。

固定长度的List

Arrays.asList(Object… a)方法可以将一个数组或者指定个数的对象转换成一个List集合,这个集合既不是ArrayList的实现类,也不是Vector的实现类,而是Arrays的内部类ArrayList的实例。

package FirstTime;

import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;

public class ListTest {

    public static void main(String[] args) {
        List<Object> arrayList = Arrays.asList("lkjhyyuj","sxdcfvgbtyh","aqa","eftds","ioljhtdddsaa","dd","rtrty");
        arrayList.sort((obj1,obj2)->((String)obj1).length()-((String)obj2).length());
        System.out.println(arrayList);
        arrayList.replaceAll(obj->((String)obj).length());
        System.out.println(arrayList);
        ListIterator<Object> listIterator = arrayList.listIterator();
        //listIterator.add("-------");//Arrays.ArrayList是一个固定长度的List集合,程序只能访问集合里的元素,不能增删
        listIterator.forEachRemaining(System.out::println);
    }

}

Queue集合

QUEUE API

boolean add(E e)

E   element():Retrieves, but does not remove, the head of this queue.

boolean offer(E e):Inserts the specified element into this queue if it is possible to do so immediately without violating capacity restrictions.

E   peek():Retrieves, but does not remove, the head of this queue, or returns null if this queue is empty.

E   poll():Retrieves and removes the head of this queue, or returns null if this queue is empty.

E   remove():Retrieves and removes the head of this queue.

Deque的API

MAP

Property

Properties类是Hashtable类的子类,正如它的名字所暗示的,该对象在处理属性文件时特别方便(Windows操作平台上的ini文件就是一种属性文件)。Properties类可以把Map对象和属性文件关联起来,从而可以把Map对象中的key-value对写入属性文件中,也可以把属性文件中“属性名=属性值”加载到Map对象中。由于属性文件里的属性名、属性值只能是字符串类型,所以Properties里的key、value都是字符串类型。该类提供了如下三个方法来修改Properties里的key、value值。

提示:
Properties相当于一个key、value都是String类型的Map。

①String getProperty(String key):获取Properties中指定属性名对应的属性值,类似于Map的get(Object obj)方法。

②String getProperty(String key,String defaultValue):该方法与前一个方法基本相似。该方法多一个功能,如果Properties中不存在指定的key时,则该方法指定默认值。

③Object setProperties(String key,String value):设置属性值,类似于Hashtable的put()方法。

④void load(InputStream inStream):从属性文件(输入流)中加载key-value对,吧加载的key-value对追加到Properties里(Properties树Hashtable的子类,它不保证key-value对之间的次序)。

⑤void store(OutputStream out , String comments):将Properties中的key-value对输出到指定的属性文件(以输出流表示)中。

package ObjectOrient;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.InvalidPropertiesFormatException;
import java.util.Properties;

public class PropertyTest {

    public static void main(String[] args) throws InvalidPropertiesFormatException, FileNotFoundException, IOException {
        Properties properties = new Properties();
        properties.loadFromXML(new FileInputStream("E:/JAVA/JAVABASE/src/ObjectOrient/Property.xml"));
        properties.setProperty("nucdsn", "John");
        properties.setProperty("iefnwi", "jkdnci");
        properties.setProperty("ncdkscn", "mcisndc");
        properties.setProperty("cdsicji", "ftps");
        properties.storeToXML(new FileOutputStream("E:/JAVA/JAVABASE/src/ObjectOrient/Property.xml"), "UTF-8");
        System.out.println(properties);
    }

}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>UTF-8</comment>
<entry key="cdsicji">ftps</entry>
<entry key="name">John</entry>
<entry key="nucdsn">John</entry>
<entry key="ncdkscn">mcisndc</entry>
<entry key="protocol">ftps</entry>
<entry key="iefnwi">jkdnci</entry>
<entry key="from">jkdnci</entry>
<entry key="to">mcisndc</entry>
</properties>

WeakHashMap

WeakHashMap与HashMap的用法基本相似。
与HashMap的区别在于,HashMap的key保留了对实际对象的强引用,这意味着只要该HashMap对象不被销毁,该HashMap的所有key所引用的对象就不会被回收,HashMap也不会自动删除这些key所对应的key-value对;
WeakHashMap的key只保留了对实际对象的弱引用,这意味着如果WeakHashMap对象的key所引用的对象没有被其他强引用变量所引用,则这些key所引用的对象可能被垃圾回收,WeakHashMap也可能自动删除这些key所对应的key-value。

WeakHashMap中的每个key对象只有持有对实际对象的弱引用,因此,当垃圾回收该key所对应的实际对象之后,WeakHashMap会自动删除该key对应的key-value对。

IdentityHashMap

这个Map实现类的实现机制与HashMap基本相似,但它在处理两个key相等时比较独特:在IdentityHashMap中,当且仅当两个key严格相等(key1 == key2)时,IdentityHashMap才认为两个key相等。对于普通的HashMap而言,只要key1和key2通过equals()方法比较返回true,且它们的hashCode值相等即可。

IdentityHashMap提供了与HashMap基本相似的方法,也允许使用null作为key和value。与HashMap相似:IdentityHashMap也不保证key-value对之间的顺序,更不能保证它们的顺序随时间的推移保持不变。

EnumMap实现类

EnumMap是一个与枚举类一起使用的Map实现,EnumMap中的所有key都必须是单个枚举类的枚举值,创建枚举类必须显式或隐式地指定它对应的枚举类。EnumMap有如下特征:

EnumMap在内部以数组形式保存,所以这种形式非常紧凑、高效。
EnumMap根据key的自然顺序(即枚举值在枚举类中定义顺序)来维护key-value对顺序。当程序通过keySet()、entrySet()、values()等方法遍历EnumMap时可以看到这种顺序。
EnumMap不允许使用null作为key,但允许使用null作为value。如果试图使用null作为key时将抛出NullPointerException一次。
与创建普通Map有所区别的是,创建EnumMap必须指定一个枚举类,从而将该EnumMap和指定枚举类关联起来。

TreeMap

TreeMap底层是根据红黑树的数据结构构建的,默认是根据key的自然排序来组织(比如integer的大小,String的字典排序)。所以,TreeMap只能根据key来排序,是不能根据value来排序的(否则key来排序根本就不能形成TreeMap)。

Collections

排序操作

Collections同一个了如下常用的类方法用于对List集合元素进行排序。

void reverse(List list):反转List集合中元素次序
void shuffle(List list):对List集合元素进行随机排序(shuffle方法模拟了“洗牌”动作)
void sort(List list):根据元素的自然顺序对指定List集合的元素进行升序排序
void sort(List list ,Comparator c):根据指定Comparator产生的顺序对List集合元素进行排序
void swap(List list , int i ,int j):将指定List集合中的i处元素和j处元素进行交换
void rotate(List list ,int distance):当distance为正数时,将list集合的后distance“整体”移到前面;当distance为负数时,将list集合的钱distance元素“整体”移到后面。该方法不会改变集合长度。

查找、替换操作

Collections还提供了常用于查找、替换集合元素的类方法。
①int binarySearch(List list , Object key):使用二分搜索法搜索指定的List集合,以获得指定对象在List集合中的索引。如果要使该方法可以正常工作,则必须保证List中的元素处于有序状态。
②Object max(Collection coll):根据元素的自然顺序,返回给定集合中的最大元素。
③Object max(Collection coll, Comparator comp):根据Comparator指定的顺序,返回给定集合中的最大元素
④Object min(Collection coll):根据元素的自然排序,返回给定集合中的最小元素
⑤Object min(Collection coll,Comparator comp):根据Comparator指定的顺序,返回给定集合中最小元素。

同步控制

Collections类中提供了多个synchronizedXxx()类方法,该方法可以将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合的线程安全问题。

Java中常用的集合框架中的实现类HashSet、TreeSet、ArrayList、ArrayDeque、HashMap和TreeMap都是线程不安全的。如果有多个线程访问它们,而且有超过一个的线程试图修改它们,则存在线程安全的问题。Collections提供了多个类方法可以把它们包装成线程同步的集合。

HashMap<Object,Object> hashMap = (HashMap<Object, Object>) Collections.synchronizedMap(new HashMap<>());

设置不可变集合

Collections提供了如下三个类方法来返回一个不可变集合。

emptyXxx():返回一个空的、不可变的集合对象,此处的集合即可以是List也可是SortedSet、Set,还可以是Map、SortedMap。
singletonXxx():返回一个只包含指定对象(只有一个或一项元素)的、不可变的集合对象,此处的集合既可以是List,还可以是Map。
unmodifiableXxx():返回指定集合对象的不可变试图。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值