Java集合Set,List和Map等
1 Java集合框架
因为Java是面向对象的语言,对事物的体现都是以对象的形式,为了方便对多个对象的操作,就要对对象进行存储。另一方面,使用Array存储对象方面具有一些弊端 。Java集合就像一个容器,可以把多个对象的引用放入容器中,它们可以帮我们方便地组织和管理一组对象。
数据的弊端:①数组初始化后,就确定长度了(长度不可改变,便于扩展)②声明时的类型,就决定了进行元素初始化时的类型③提供的属性和方法少,不便于进行添加、删除、插入等操作,且效率不高,也无法直接获取存储元素的个数④数组存储的数据是有序的、可以重复的(比较单一)。
Java 集合类可以用于存储数量不等的多个对象,还可用于保存具有映射关系的关联数组。
Java 集合可以分为两大集合体系Collection和Map。集合框架图如下。
2 Collection接口
Collection接口:是单列数据,定义了存取一组对象的方法和集合。Collection 接口是 List、Set 和 Queue 接口的父接口,该接口里定义的方法 既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合。 在 Java5 之前,Java 集合会丢失容器中所有对象的数据类型,把所有对象都 当成 Object 类型处理;从 JDK 5.0 增加了泛型以后,Java 集合可以记住容器中对象的数据类型。
set接口:存放无序不可重复的数据。set接口下有HashSet,LinkedHashSet,TreeSet
List接口:存放有序可以重复数据。List接口下有ArrayList,Vector,LinkedList
Collection的常用API:
API | 描述 |
boolean add(E e) | 添加元素 |
boolean addAll(Collection<? extends E> c) | 添加集合元素 |
void clear() | 清除集合中的所有元素 |
boolean remove(Object o) | 删除集合中的某一个元素,通过元素的equals方法判断是否是要删除的那个元素 |
boolean removeAll(Collection<?> c) | 删除多个元素,也就是取当前集合的差集 |
boolean isEmpty() | 判断集合中的元素是否为空 |
boolean contains(Object o) | 判断集合中是否包含该元素,是通过元素的equals方法来判断是否是同一个对象 |
boolean containsAll(Collection c) | 也是调用元素的equals方法来比较的。拿两个集合的元素挨个比较。 |
Iterator<E> iterator() | 返回迭代器对象,用于集合遍历 |
int size() | 获取集合中元素个数 |
Object[] toArray() | 集合转换数组 |
Arrays.asList(T… t) | 数组转换集合 |
2.1 List接口
特点:有序(存储顺序和取出顺序一致),可重复。
List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
2.1.1 ArrayList
优点:底层数据结构是数组,查询快,增删慢。缺点:线程不安全,效率高
常用API:
API | 描述 |
boolean add(E e) | 添加单个元素 |
void add(int index, E element) | 在指定的下标处添加元素 |
E get(int index) | 通过下标来获取元素 |
int indexOf(Object o) | 获取集合某一元素的下标(从左到向查找) |
int lastIndexOf(Object o) | 获取集合某一元素的下标(从右向左查找) |
boolean remove(Object o) | Collection接口中的方法,根据元素删除 |
E remove(int index) | List接口中的方法,根据下标删除,E代表返回删除对象 |
boolean retainAll(Collection<?> c) | 交集 |
E set(int index, E element) | 修改某一下标对应的元素 |
List<E> subList(int fromIndex, int toIndex) | 返回当前集合的一个子集,从开始下标(包含)到结束下标(不包含) |
注意:要删除int类型要用Integer()方法,因为传int类型的话删除的得是索引。
本质上,ArrayList是对象引用的一个”变长”数组 ,在JDK1.7:ArrayList像饿汉式,直接创建一个初始容量为10的数组 。在JDK1.8:ArrayList像懒汉式,一开始创建一个长度为0的数组,当添加第一个元素时再创建一个始容量为10的数组 。
Arrays.asList(…) 方法返回的 List 集合,既不是 ArrayList 实例,也不是 Vector 实例。 Arrays.asList(…) 返回值是一个固定长度的 List 集合
2.1.2 LinkedList
优点:底层数据结构是链表,查询慢,增删快。 缺点:线程不安全,效率高
常用API:
API | 描述 |
void addFirst(E e) | 添加第一个位置 |
void addLast(E e) | 添加在末尾 |
E getLast() | 获取最后一个元素 |
E getFirst() | 获取第一个位置元素 |
E removeFirst() | 删除第一个元素 => remove() 删除此列表的头(第一个元素) |
E removeLast() | 删除最后一个元素 |
LinkedList 是个双向链表,内部没有声明数组,而是定义了Node类型的first和last, 用于记录首末元素。同时,定义内部类Node,作为LinkedList中保存数据的基本结构。Node除了保存数据,还定义了两个变量:prev变量记录前一个元素的位置,next变量记录下一个元素的位置 。
private static class Node<E> {E item;Node<E> next;Node<E> prev;Node(Node<E> prev, E element, Node<E> next) {this.item = element;this.next = next;this.prev = prev;}}
2.1.3 Vector
优点:底层数据结构是数组,查询快,增删慢。 缺点:线程安全,效率低
常用API:void addElement(E obj) ; //添加元素的方法。 int capacity() ; //默认为10
2.1.4 ArrayList,LinkedList,Vector的异同
(1)ArrayList和LinkedList:都是线程不安全的,相对于线程安全的Vector,执行效率要高。ArrayList是基于动态数据的数据结构,LinkedList是基于链表的数据结构。随机访问查询,ArrayList的效率要比LinkedList高,因为LinkedList要移动指针,对于新增和删除,LinkedList效率比较高,因为ArrayList要移动数据
(2)ArrayList和Vector:他们几乎是相同的,唯一的区别是Vector是同步类,属于强同步,正常情况下使用ArrayList而不是Vector,因为同步可以由我们自己控制。Vector每次扩容请求增大2倍空间,ArrayList请求增大1.5倍空间。
2.2 Set接口
特点:无序(存储顺序和取出顺序不一致),唯一
2.2.1 HashSet
底层数据结构是哈希表(无序,唯一)。
保证唯一性:依赖hashCode()和equals()方法。使用HashCode算法,获取对象存储的位置。如果没有,就会将对象存储在这个位置。如果有(对象的HashCode一样),会调用equals方法。
如果两个对象相同,那么它们的hashCode值一定要相同;如果两个对象的hashCode相同,它们并不一定相同。
public class TestHashSet {@Testpublic void test2() {HashSet set = new HashSet();set.add(new Person("小明",20));set.add(new Person("小张",23));set.add(new Person("小明",20));
// set.add("abc");
// System.out.println("abc".hashCode()); //
// System.out.println(new String("abc").hashCode()); //System.out.println(set.size()); //输出2System.out.println(set);}
}
class Person{String name;int age;@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + age;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Person other = (Person) obj;if (age != other.age)return false;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;return true;}}
HashSet底层也是数组,初始容量为16,使用率超过0.75,则扩容为原来的2倍。
向HashSet中添加元素的过程:①向HashSet 存入一个元素,会调用该对象的hashCode方法得到hashCode值,根据这个hashCode值通过某种散列函数觉得这个对象在HashSet 底层数组中的存储位置。②如果2个元素的hashCode值相等,继续调用equals方法,如果equals方法结果为true,添加失败;如果为false,那么会保存该元素,但是该数组的位置已经有元素了,那么会通过链表的方式继续链接。
总结:hashCode不一样会添加元素,不会验证euqals方法;hashCode一样会验证equals方法,如果相同则不会添加后元素,否则会添加后元素。
2.2.2 LinkedHashSet
继承自HashSet,底层数据结构是链表和哈希表,由链表保证元素有序,由哈希表保证元素唯一。根据元素的 hashCode 值来决定元素的存储位置。
与hashSet区别:遍历时LinkedHashSet比hashSet效率高;插入和删除元素hash效率高。
2.2.3 TreeSet
TreeSet 底层数据结构是红黑树。(唯一,有序)。是 SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态。
特点:(1)TreeSet添加元素的类型要一致。
(2)输出的顺序可以按一定的规则输出。
(3)排序方式:①自然排序 实现Comparable接口;②定制排序 实现Comparator 接口
public class Test1 {//自然排序测试@Testpublic void test() {TreeSet<Employee> tree = new TreeSet<>();tree.add(new Employee("cc",10,new MyDate(2010,1,1)));tree.add(new Employee("ff",10,new MyDate(2011,1,1)));tree.add(new Employee("a",8,new MyDate(2010,1,5)));tree.add(new Employee("e",13,new MyDate(2013,1,1)));tree.add(new Employee("cca",12,new MyDate(2015,5,1)));System.out.println(tree);}//自定义排序测试@Testpublic void test1() {TreeSet<Employee1> tree = new TreeSet<>(new Comparator<Employee1>() {//比较o1和o2的大小:如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2。@Overridepublic int compare(Employee1 o1, Employee1 o2) {if(o1.getBirthday().getYear() == o2.getBirthday().getYear()) {if(o1.getBirthday().getMonth()==o2.getBirthday().getMonth()) {if(o1.getBirthday().getDay()==o2.getBirthday().getDay()) {return 0;}return o1.getBirthday().getDay()-o2.getBirthday().getDay();}return o1.getBirthday().getMonth()-o2.getBirthday().getMonth();}return o1.getBirthday().getYear() - o2.getBirthday().getYear();}});tree.add(new Employee1("cc",10,new MyDate(2010,1,1)));tree.add(new Employee1("ff",10,new MyDate(2011,1,1)));tree.add(new Employee1("a",8,new MyDate(2010,1,5)));tree.add(new Employee1("e",13,new MyDate(2013,1,1)));tree.add(new Employee1("cca",12,new MyDate(2015,5,1)));System.out.println(tree);}
}
class Employee implements Comparable<Employee>{private String name;private int age;private MyDate birthday;public Employee() {super();}public Employee(String name, int age, MyDate birthday) {super();this.name = name;this.age = age;this.birthday = birthday;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public MyDate getBirthday() {return birthday;}public void setBirthday(MyDate birthday) {this.birthday = birthday;}@Overridepublic String toString() {return "[name=" + name + ", age=" + age + ", birthday=" + birthday + "]";}@Overridepublic int compareTo(Employee o) {return this.name.compareTo(o.name);}}class MyDate{private int month;private int day;private int year;public MyDate() {}public MyDate(int year, int month, int day) {this.month = month;this.day = day;this.year = year;}public int getMonth() {return month;}public void setMonth(int month) {this.month = month;}public int getDay() {return day;}public void setDay(int day) {this.day = day;}public int getYear() {return year;}public void setYear(int year) {this.year = year;}@Overridepublic String toString() {return "[" +year + "-"+ month + "-" + day + "]";}}class Employee1{private String name;private int age;private MyDate birthday;public Employee1() {super();}public Employee1(String name, int age, MyDate birthday) {super();this.name = name;this.age = age;this.birthday = birthday;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public MyDate getBirthday() {return birthday;}public void setBirthday(MyDate birthday) {this.birthday = birthday;}@Overridepublic String toString() {return "[name=" + name + ", age=" + age + ", birthday=" + birthday + "]";}}
3 Map接口
Map接口:双列数据,保存具有映射关系的K-V对的集合。Map接口有三个比较重要的实现类,分别是HashMap、TreeMap和HashTable。Map接口和Collection接口是并列的。
Map 中的 key 和 value 都可以是任何引用类型的数据 。因为Map 中的 key 用Set来存放,所以不允许重复,即同一个 Map 对象所对应的类,须重写hashCode()和equals()方法。key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到唯一的、确定的。
3.1 HashMap
HashMap是 Map 接口使用频率最高的实现类。 允许使用null键和null值,与HashSet一样,不保证映射的顺序。
所有的key构成的集合是Set:无序的、不可重复的。所以,key所在的类要重写: equals()和hashCode() 。所有的value构成的集合是Collection:无序的、可以重复的。所以,value所在的类 要重写:equals() 。
一个key-value构成一个entry,所有的entry构成的集合是Set:无序的、不可重复的。
HashMap 判断两个 key 相等的标准是:两个 key 通过 equals() 方法返回 true, hashCode 值也相等。HashMap 判断两个 value相等的标准是:两个 value 通过 equals() 方法返回 true。
Map接口常用API如下:
添加删除操作API | 描述 |
Object put(Object key,Object value) | 添加元素 |
Object remove(Object key) | 删除 |
void putAll(Map t) | 添加map集合 |
void clear() | 清除 |
查询操作API | 描述 |
Object get(Object key) | 通过key获取vclue |
boolean containsKey(Object key) | 判断key在map集合是否存在 |
boolean containsValue(Object value) | 判断value在map集合是否存在 |
int size() | map集合元素的个数 |
boolean isEmpty() | 是否为空 如果空返回是true |
boolean equals(Object obj) | 比较 |
集合操作 | 描述 |
Set keySet() | 键的集合 |
Collection values() | 值的集合 |
Set entrySet() | 键\值集合 |
注意:如果key相同,后者会替换前者。与HashSet不同,HashSet相同的话不添加后者
HashMap存储结构在JDK7以前是:数组+链表,在JDK8后是:数组+链表+红黑树
JDK 1.8之前HashMap的存储结构说明:内部存储结构是数组和链表的结合。 当实例化一个HashMap时,系统会创建一个长度为Capacity(哈希表中被称为容量 )的Entry数组,数组中可以存放元素的位置称为“桶(bucket)”,每个桶有自己的索引,系统可以根据索引快速的找到桶中的元素。每个桶存储一个元素,即一个Entry对象,但是每个Entry对象可以带一个引用变量,用于指向下一个元素。所以在一个桶中,就有可能生成一个Entry链,新添加的元素作为链表的head。
添加元素的过程:①首先计算entry(key,value)中key的hashCode值,得到在底层Entry数组中要存储的位置,如果这个位置上没有元素,直接添加成功;如果这个位置上已经存在一个entry1或者存在一个entry链表了,则循环比较每一个entry中你的key和要插入的entry的key,如果hash值不同,添加到entry链表;如果hash值相同,再比较equals,如果相同则用待插入的entry的value替换链表中与他equals相同的entry的value,如果遍历一遍以后发现所有的equals都不相等,则插入链表,这个entry指向原有的entry元素。
HashMap扩容:当HashMap中的元素越来越多的时候,因为数组的长度时固定的,那么hash冲突的概率也越来越高,为了提高查询效率就需要对数组进行扩容。当 HashMap 中的元素个数超过数组长度的loadFactor (默认值是0.75)就会进行扩容。默认数组大小DEFAULT_INITIAL_CAPACITY 是16,当HashMap中元素个数超过16*0.75=12个时就进行扩容,扩大一倍,即为32。在HashMap数组扩容之后,最消耗性能的点就是原数组中的数据必须重新计算其在新数组中的位置并插入。所以如果我们已经预知HashMap中元素的个数,预设元素的个数能有效提高HashMap的性能
JDK 1.8之后HashMap的存储结构说明:内部存储结构是数组+链表+红黑树,当实例化一个HashMap的时候,会初始化initialCapacity和loadFactor,在插入第一个entry的时候,系统创建一个长度为initialCapacity的Node数组,数组中可以存放元素的位置称为“桶(bucket)”,每个桶有自己的索引,系统可以根据索引快速的找到桶中的元素。每个桶存储一个元素,即一个Node对象,但是每个Node对象可以带一个引用变量,用于指向下一个元素。所以在一个桶中,就有可能生成一个Node链。也由可能是一个个TreeNode对象,每个TreeNode对象有两个叶子节点left和right。新添加的元素就可能作为链表的最后一个或者树的叶子节点。
HashMap扩容:当HashMap中的元素越来越多的时候,因为数组的长度时固定的,那么hash冲突的概率也越来越高,为了提高查询效率就需要对数组进行扩容。当 HashMap 中的元素个数超过数组长度的loadFactor (默认值是0.75)就会进行扩容。默认数组大小DEFAULT_INITIAL_CAPACITY 是16,当HashMap中元素个数超过16*0.75=12个时就进行扩容,扩大一倍,即为32。在HashMap数组扩容之后,最消耗性能的点就是原数组中的数据必须重新计算其在新数组中的位置并插入。
HashMap树形化:①当HashMap中其中一个链的对象个数达到了8个,如果Capacity还没有到64,会进行扩容解决。②如果Capacity已经到64那么这个链表会变成树,节点的类型也有Node变成TreeNode类型。如果当映射关系被移除后,下次resize方法时判断树的结点个数低于6个,也会把树再转为链表。
JDK 1.8之后HashMap与JDK 1.8之前HashMap的比较:①JDK 1.8默认情况下,先不创建长度为16的数组,只有在第一次插入数据的时候才创建长度为16的数组 ②数组为Node类型,在JDK 1.7中称为Entry类型 ③JDK 1.8形成链表结构时,新添加的key-value对在链表的尾部(七上八下) ④当数组指定索引位置的链表长度>8时,且map中的数组的长度> 64时,此索引位置上的所有key-value对使用红黑树进行存储。
loadFactor负载因子的值对HashMap的影响:负载因子的大小决定了HashMap的数据密度,负载因子越大发碰撞的概率就越大,导致链表长度越长,造成查询和插入时比较的次数越多,性能下降;负载因子越小,数据密度越小,就越容易触发扩容,碰撞的概率越小,数组中链表越短,查询和插入时比较的次数会减少,性能更高,但是会浪费一定的内存空间,并且经常扩容对性能也有影响。初始化可以预设大一点。
3.2 LinkedHashMap
在HashMap存储结构的基础上,使用了一对双向链表来记录添加 元素的顺序 。与LinkedHashSet类似,LinkedHashMap 可以维护 Map 的迭代,存储顺序和输出顺序一致。
public class TestLinkedHashMap{@Testpublic void test2(){LinkedHashMap link = new LinkedHashMap();link.put("aa", 90); link.put("cc",88);link.put(new Date(),99);link.put(null, null);//keysetSet keys = link.keySet();for(Object o : keys) {System.out.println(o+"===="+link.get(o));}}
}
3.3 TreeMap
TreeMap存储 Key-Value 对时,需要根据 key-value 对进行排序 ,按照添加的key属性排序,TreeSet底层使用红黑树结构存储数据。
自然排序:实现接口Comparable重写int CompareTo(Object obj)方法;
定制排序:实现接口Comparator重写int CompareTo(Object obj1,Object obj2)方法;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.junit.Test;public class TestTreeMap {@Testpublic void test2() {Comparator com = new Comparator() {@Overridepublic int compare(Object o1, Object o2) {if(o1 instanceof Person && o2 instanceof Person) {Person p1 = (Person)o1;Person p2 = (Person)o2;return p1.name.compareTo(p2.name);}return 0;}};Map tree =new TreeMap(com);tree.put(new Person("a"),90);tree.put(new Person("e"),30);tree.put(new Person("d"),50);tree.put(new Person("c"),70);Set set = tree.keySet();Iterator it = set.iterator();while(it.hasNext()) {it.next();}System.out.println(tree);}//自然排序@Testpublic void test1() {TreeMap tree =new TreeMap();tree.put(new Person("a"),90);tree.put(new Person("e"),30);tree.put(new Person("d"),50);tree.put(new Person("c"),70);System.out.println(tree);}
}
class Person1 {String name;public Person1(String name) {this.name = name;} @Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Person other = (Person) obj;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;return true;}@Overridepublic String toString() {return "Person [name=" + name + "]";}}
class Person implements Comparable{String name;public Person(String name) {super();this.name = name;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Person other = (Person) obj;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;return true;}@Overridepublic int compareTo(Object o) {if(o instanceof Person) {Person p = (Person)o;return this.name.compareTo(p.name);}return 0;}@Overridepublic String toString() {return "Person [name=" + name + "]";}
}
3.4 HashTable
与HashMap相同不能保证顺序,key值相同替换,但是他是线程安全的。
Hashtable实现原理和HashMap相同,功能相同。底层都使用哈希表结构,查询速度快,很多情况下可以互用。与HashMap不同,Hashtable 不允许使用 null 作为 key 和 value。
它的子类properties用来操作属性文件,如下
public void TestProperties throws FileNotFoundException, IOException {public static void main(String[] args){//创建属性文件类的对象Properties pro = new Properties();//以流的方式读取文件到内存pro.load(new FileInputStream(new File("jdbc.properties")));String name = pro.getProperty("jdbc.username");String password = pro.getProperty("jdbc.password");System.out.println(name+ "--" + password);}
}
3.5 Properties
Properties 类是 Hashtable 的子类,该对象用于处理属性文件。因为属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key 和 value 都是字符串类型。存取数据时,建议使用setProperty(String key,String value)方法和 getProperty(String key)方法 。
Properties pros = new Properties();pros.load(new FileInputStream("test.properties"));String user = pros.getProperty("user");System.out.println(user);
4 Collections工具类
Collections工具类是一个操作Set,List和Map等集合的工具类,Collections提供了一系列静态的方法对集合中的元素进行排序,查询和修改等操作,还提供了对集合对象设置不可变,实现同步控制等方法。
方法 | 描述 |
reverse(List) | 反转List中元素的顺序 |
sort(List) | 根据元素的自然排序对指定List集合元素按升序排序 |
sort(List,Comparator) | 根据指定的Comparator产生的顺序对List集合元素进行排序 |
swap(List,int,int) | 将指定List集合中的i处元素和j处元素进行交换 |
shuffle(List) | 对List集合元素进行随机排序 |
int frequency(Collection,Object) | 返回指定集合中指定元素的出现次数 |
Object max(Collection) | 根据元素的自然排序,返回给定集合中的最大元素 |
Object max(Collection,Comparator) | 根据Comparator指定的顺序,返回给定集合中的最大元素 |
Object min(Collection) | 根据元素的自然排序,返回给定集合中的最小元素 |
Object min(Collection,Comparator) | 根据Comparator指定的顺序,返回给定集合中的最小元素 |
void copy(List dest,List src) | 将src中的内容复制到dest中 |
boolean replaceAll(List list, Object oldVal,Object newVal ) | 使用新值替换 List 对象的所有旧值 |
ListArrays.asList(T...t) 数组转集合 list.toArray(集合转数组) Arrays.sort(array)数组排序
尽量不要使用ListArrays.asList(T...t) 数组转集合,因为该方法返回固定长的List,不支持add和remove操作,该方法返回的List与传入的数组是映射关系,set/get直接操作数组,List也会改变。有以下替代方案:
Integer[] array = {1,2}; List<Integer> list = new ArrayList<>(Arrays.asList(array)); |
List<Integer> list = new ArrayList<>(); Integer[] array = {1,2}; Collections.addAll(list,array); |
int[] array = {1,2}; List<integer> list = Arrays.stream(array).bosxed().collect(Collectors.toList()); |
List,Integer[],int[]相互转换// int[] 转 List<Integer>List<Integer> list = Arrays.stream(data).boxed().collect(Collectors.toList());// Arrays.stream(arr) 可以替换成IntStream.of(arr)。// 1.Arrays.stream将int[]转换成IntStream。// 2.IntStream中的boxed()装箱。将IntStream转换成Stream<Integer>。// 3.Stream的collect(),将Stream<T>转换成List<T>,因此正是List<Integer>。// int[] 转 Integer[]Integer[] integers = Arrays.stream(data).boxed().toArray(Integer[]::new);// 前两步同上,此时是Stream<Integer>。// 然后使用Stream的toArray,传入IntFunction<A[]> generator。// 这样就可以返回Integer数组。// 不然默认是Object[]。// List<Integer> 转 Integer[]Integer[] integers2 = list1.toArray(new Integer[0]);// 调用toArray。传入参数T[] a。// List<Integer> 转 int[]int[] arr1 = list1.stream().mapToInt(Integer::valueOf).toArray();// 想要转换成int[]类型,就得先转成IntStream。// 这里就通过mapToInt()把Stream<Integer>调用Integer::valueOf来转成IntStream// 而IntStream中默认toArray()转成int[]。// Integer[] 转 int[]int[] arr2 = Arrays.stream(integers1).mapToInt(Integer::valueOf).toArray();// 思路同上。先将Integer[]转成Stream<Integer>,再转成IntStream。// Integer[] 转 List<Integer>List<Integer> list2 = Arrays.asList(integers1);String数组与List集合之间的转换较容易// 最简单的方式。String[]转List<String>也同理。String[] strings1 = {"w", "a", "n"};// String[] 转 List<String>List<String> listStr = Arrays.asList(strings1);// List<String> 转 String[]String[] stringStr = listStr.toArray(new String[0]);
4 Iterator迭代器接口
Iterator对象成为迭代器,是设计模式的一种,主要作用就是用于遍历collection集合中的元素。
迭代器模式的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。迭代器模式,就是为容器而生。
Collection接口继承了java.lang.Iterable接口,这个接口有个iterator方法,所以所有实现了Collection接口的集合类都有一个iterator方法。
iterator仅仅用于遍历集合,iterator本身不提供承载对象的能力,所以创建Iterator对象,必须由一个被迭代的集合。集合对象每次调用iterator方法都得到一个全新的迭代对象,默认游标都在集合的第一个元素之前
4.1 Iterator接口的方法
方法 | 描述 |
hasNext() | 如果iterator还有元素则返回true,否则返回false(注意,这时上面的那个指针位置不变) |
next() | 返回这个iterator的下一个元素,同时上面的指针向后移动一位。 |
remove | 删除 iterator 内指针的前1个元素,前提是至少执行过1次next(); |
注意:在调用next方法之前必须要调用hasNext方法检测,否则如果下一条没有记录,调用next则会抛异常