集合
集合
一、集合概述
1、为什么要学习集合?
数组可以储存多个对象,但在无法确定需要保存多少个对象时,数组将不再适用,因为数组的长度不可变。
所以为了保存这些数目不确定的对象,Java中提供了集合,集合可以存储任意类型的对象,并且长度可变。
2、定义
Java中的集合就像一个容器,专门用来存储Java对象。
3、说明
集合对象可以是任意的数据类型,并且长度可变
4、注意
这些集合类都位于java.util包中
5、集合分类
5.1 单列集合Collection
(1)单列集合根接口,用于存储一系列符合某种规则的元素
(2)Collection集合有两个重要的子接口,分别是List和Set
(3)List集合的特点是元素有序、可重复。该接口的主要实现类有ArrayList和LinkedList
(4)Set集合的特点是元素无序并且不可重复。该接口的主要实现类有HashSet和TreeSet
5.2 双列集合Map
(1)双列集合根接口,用于存储具有键(key)、值(Value)映射关系的元素
(2)Map集合中每个元素都包含一对键值,并且Key唯一,在使用Map集合时通过指定的Key找到对应的Value
(3)Map接口的主要实现类有HashMap和TreeMap
二、Collection接口
1、相关方法
boolean add(Object o) 向集合中添加一个元素
boolean addAll(Collection c) 将指定集合c中的所有元素添加到该集合中
void clear() 删除该集合中的所有元素
boolean remove(Object o) 删除该集合中指定的元素
boolean removeAll(Collection c) 删除该集合中包含指定集合c中的所有元素
boolean isEmpty() 判断该集合中是否为空
boolean contains(Object o) 判断该集合中是否包含某个元素
boolean containsAll(Collection c) 判断该集合中是否包含指定集合c中的所有元素
int size() 获取该集合元素个数
Iterator iterator 返回在该集合的元素上进行迭代的迭代器(Iterator),用于遍历该集合所有元素
Stream stream() 将集合源转换为有序元素的流对象(JDK 8新方法)
泛型:指的是集合中存储元素的数据类型
public class Demo1{
public static void main(String[] args){
//创建集合对象
Collection<String> list = new ArrayList<String>();
//boolean add(Object o) 向集合中添加一个元素
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
list.add("eee");
System.out.println(list);
//int size() 获取该集合元素个数
int size = list.size();
System.out.println(size);
//boolean isEmpty() 判断该集合中是否为空
boolean flag = list.isEmpty();
System.out.println(flag);
//boolean contains(Object o) 判断该集合中是否包含某个元素
flag = list.contains("eee");
System.out.println(flag);
//boolean remove(Object o) 删除该集合中指定的元素
boolean b = list.remove("bbb");
System.out.println(b);
System.out.println(list);
//boolean removeAll(Collection c) 删除该集合中包含指定集合c中的所有元素
Collection<String> list3 = new ArrayList<String>();
list3.add("aaa");
list3.add("ccc");
//boolean containsAll(Collection c) 判断该集合中是否包含指定集合c中的所有元素
boolean flag = list.containsAll(list3);
System.out.println(flag);
//将list集合中包含list3集合所有的元素都删除
list.removeAll(list3);
System.out.println(list);
//boolean addAll(Collection c) 将指定集合c中的所有元素添加到该集合中
Collection<String> list2 = new ArrayList<String>();
list2.addAll(list);
System.out.println(list2);
//void clear() 删除该集合中的所有元素
list2.clear();
System.out.println(list2);
}
}
三、List接口
1、List接口简介
1.1 定义
List接口继承自Collection接口,是单列集合的一个重要分支,习惯性的会将实现了List接口的对象称为List集合
1.2 特点
(1)List集合中允许出现重复元素,所有元素是以一种线性方式进行存储的,在程序中可以通过索引(类似于数组中的元素角标)来访问集合中的元素。
(2)List集合还有一个特点就是元素有序,即元素的存入顺序和取出顺序一致
1.3 List集合常用方法
void add(int index,Object element) 将元素element插入在List集合的指定索引位置
boolean addAll(int index,Collection c) 将集合c包含的所有元素插入到List集合的指定索引位置
Object get(int index) 返回集合索引index处的元素
Object remove(int index) 删除index索引处的元素
Object set(int index,Object element) 将索引index处元素替换成element元素,并将替换后的元素返回
int indexOf(Object o) 返回对象o在List集合中首次出现的位置索引
int lastIndexOf(Object o) 返回对象o在List集合中最后一次出现的位置索引
List subList(int fromIndex,int toIndex) 返回从索引fromIndex(包括)到toIndex(不包括)处所有元素集合组成的子集合
Object[] toArray() 将集合元素转换成数组
default void sort(Comparator<? super E>c) 根据指定的比较器规则对集合元素排序
1.4 相关代码
public class Demo2{
public static void main(String[] args){
//创建集合对象
List<String> list = new ArrayList<String>();
list.add("aaa");
list.add("bbb");
//void add(int index,Object element) 将元素element插入在List集合的指定索引位置
list.add(1,"ccc");
System.out.println(list) //[aaa,ccc,bbb]
//Object get(int index) 返回集合索引index处的元素
String str = list.get(0);
System.out.println(str);
//Object remove(int index) 删除index索引处的元素
String del = list.remove(0);
System.out.println(del);
System.out.println(list);
//Object set(int index,Object element)将索引index处元素替换成element元素,并将替换后的元素返回
String old = list.set(1,"ddd");
System.out.println(old);
System.out.println(list);
//int indexOf(Object o) 返回对象o在List集合中首次出现的位置索引
int index = list.indexOf("ddd");
System.out.println(index);
//int lastIndexOf(Object o) 返回对象o在List集合中最后一次出现的位置索引
list.add("ddd");
System.out.println(list);
index = list.lastIndexOf("ddd");
System.out.println(index);
System.out.println("=============================================");
//List subList(int fromIndex,int toIndex) 返回从索引fromIndex(包括)到toIndex(不包括)处所有元素集合组成的子集合
List<string> list2 = list.subList(1,list.size()-1);
System.out.println(list2);
//Object[] toArray() 将集合元素转换成数组
Object[] arr = list.toArray();
for(int i=0;i<arr.length;i++)
{
System.out.println(arr[i]);
}
//boolean addAll(int index,Collection c) 将集合c包含的所有元素插入到List集合的指定索引位置
List<String> list2 = new ArrayList<String>();
list2.add("aaa");
list2.add("eee");
list2.addAll(1,list);
//list2:[aaa,aaa,bbb,ccc,eee]
System.out.println(list2)
}
}
四、ArrayList集合
1、说明
ArrayList是List接口的一个实现类,它是程序中最常见的一种集合
ArrayList内部的数据存储结构是数组形式
2、特点
(1)由于ArrayList的存储结构,在增加或删除指定位置的元素时,会创建新的数组,效率比较低,因此不适合做大量的真删操作。
(2)这种数组结构允许程序通过索引的方式来访问元素,使用ArrayList集合在遍历和查找元素时显得非常高效。
3、优缺点
底层是数组实现的。查询快、增删慢。
4、相关代码
public class Demo03{
public static void main(String[] args){
//创建ArrayList集合对象
ArrayList<String> list = new ArrayList<String>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
//获取集合长度
int size = list.size();
System.out.println("集合的长度是"+size);
//获取元素
System.out.println(list); //[aaa,bbb,ccc,ddd]
System.out.println(list.get(0)); //aaa
System.out.println(list.get(1)); //bbb
}
}
五、LinkedList集合
1、说明
LinkedList是List接口的另一个实现类
LinkedList内部包含有两个Node类型的first和last属性的双向循环链表结构。
2、特点
由于LinkedList的存储结构,
LinkedList集合对于元素的遍历和查找效率较低。
LinkedList集合对于元素的增删操作表现出很高的效率。
3、优缺点
底层是链表实现的。增删快、查询慢
4、相关代码
public class Demo4{
public static void main(String[] args){
//创建LinkedList集合对象
LinkedList<String> list = new LinkedList<String>();
list.add("aaa");
list.add("bbb");
System.out.println(list); //[aaa,bbb]
//one
list.addFirst("ttt");
//或者
//two
list.add(0,"ttt");
System.out.println(list); //[ttt,aaa,bbb]
}
}
六、Iterator遍历集合
1、定义
Iterator接口是java集合框架中的一员,主要用于迭代访问(即遍历)Collection中的元素,因此Iterator对象也被称为迭代器。
同时也用于遍历单列集合
2、示例
Iterator iterator = list.iterator();
while(iterator.hasNext()){
Object obj = iterator.next(); //取出ArrayList集合中的元素
System.out.println(obj);
}
3、成员方法
boolean hasNext(); 判断迭代器中是否还有下一个元素
E next(); 获取迭代器中下一个元素
void remove(); 从迭代器中删除某个元素
//示例一
public class Demo5{
public static void main(String[] args){
Collection<String> coll = new ArrayList<>();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
coll.add("ddd");
//使用迭代器对集合进行遍历
//获取迭代器对象,同时将指针向后移动一位
Iterator<String> it = coll.iterator();
//boolean hasNext(); 判断迭代器中是否还有下一个元素
boolean b = it.hasNext();
System.out.println(b);
//E next(); 获取迭代器中下一个元素
String e = it.next();
System.out.println(e); //aaa
b = it.hasNext();
System.out.println(b);
e = it.next();
System.out.println(e); //bbb
b = it.hasNext();
System.out.println(b);
e = it.next();
System.out.println(e); //ccc
.....
//或者
while(it.hasNext()){
String e = it.next();
System.out.println(e);
}
}
}
//示例二
public class Demo6{
public static void main(String[] args){
Collection<String> coll = new ArrayList<>();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
coll.add("ddd");
//使用迭代器对集合进行遍历
//获取迭代器对象,同时将指针向后移动一位
Iterator<String> it = coll.iterator();
while(it.hasNext()){
String e = it.next();
System.out.println(e);
}
}
}
//示例三
public class Demo7{
public static void main(String[] args){
Collection<String> coll = new ArrayList<>();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
coll.add("ddd");
//使用迭代器对集合进行遍历
//获取迭代器对象,同时将指针向后移动一位
Iterator<String> it = coll.iterator();
//使用迭代器进行删除元素
while(it.hasNext()){
String e = it.next();
if(e.equals("bbb")){
it.remove(); //推荐的删除方式
}
}
System.out.println(coll);
}
}
七、foreach遍历集合
1、定义
foreach循环是一种更加简洁的for循环,也称增强for循环,用于遍历数组或集合中的元素
2、语法
for(容器中元素类型 临时变量 : 容器变量){
//执行语句
}
3、示例
for(Object obj : list){
System.out.println(obj);
}
4、更通俗一点的格式
for(数据类型 变量名 : 容器对象名称){
循环体语句;
}
5、示例代码
public class Demo8{
public static void main(String[] args){
//使用增强for循环遍历数组
String[] arr = {"张三","里斯","王五"};
for(String s : arr){
System.out.println(s);
}
//使用增强for循环遍历集合
Collection<Integer> coll = new ArrayList<Integer>();
coll.add(100);
coll.add(200);
coll.add(300);
coll.add(400);
for(Integer i : coll){
System.out.println(i);
}
}
}
6、JDK8版本后的forEach()方法遍历集合
6.1 定义
forEach方法是JDK8中新增的遍历集合元素的方法,根据Lambda表达式特性,该方法所需要的参数是一个函数式接口。
list.forEach(obj->System.out.println(“迭代器集合元素:” + obj));
同时针对迭代器对象也提供了一个forEachRemaining方法来进行遍历。该方法同样需要一个函数式接口。
Iterator it = list.iterator();
it.forEachRemaining(obj->System.out.println(“迭代器元素:” + obj));
public class Demo9{
public static void main(String[] args){
Collection<String> coll = new ArrayList<>();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
coll.add("ddd");
coll.forEach((String e)->{System.out.println(e);});
//JDK8版本后的迭代器对象forEach()方法遍历集合
Iterator<String> it = coll.iterator();
it.forEachRemaining((String e)->{System.out.println(e);});
}
}
八、Set接口简介
1、说明
Set接口和List接口一样,同样继承自Collection接口。
2、特点
Set接口中的元素无序,并且都会以某种规则保证存入的元素不出现重复。
3、种类
HashSet
TreeSet
九、HashSet集合
1、说明
HashSet是Set接口的一个实现类,它所存储的元素不可重复,并且无序。
2、特点
当向HashSet集合中添加一个元素时,首先会调用该元素的hashCode()方法来确定元素的存储位置,然后再调用元素对象的equals()方法来确保该位置没有重复元素。
HashSet set = new HashSet();
set.add("Jack");
set.add("Eve");
...
set.forEach(o->System.out.println(o));
3、优缺点
无索引、不能存储重复元素、存储无序。
public class Demo10{
public static void main(String[] args){
//创建HashSet集合对象
HashSet<String> hs = new HashSet<String>();
hs.add("hello");
hs.add("world");
hs.add("java");
System.out.println(hs); //[world,java,hello]
}
}
4、注意
在对对象进行处理时,可以在model层利用系统的快捷键创建hascode+equals方法,来去重。
十、TreeSet集合
1、说明
TreeSet是Set接口的另一个实现类,它内部采用平衡二叉树来存储元素,来保证TreeSet集合中没有重复的元素,并且可以对元素进行排序。
2、定义
二叉树就是每个节点最多有两个子节点的有序树,每个节点及其子节点组成的树称为子树,左侧的节点称为"左子树",右侧的节点称为"右子树",其中左子树上的元素小于它的根结点,而右子树上的元素大于它的根结点。
3、存储原理
TreeSet集合没有元素时,新增的第1个元素会在二叉树最顶层;
接着新增元素时,首先会与根结点元素比较;
如果小于根节点元素就与左边的分支比较;
如果大于根节点元素就与右边的分支比较;
以此类推
4、优缺点
底层是二叉树实现。可以进行元素的排序
public class Demo11{
public static void main(String[] args){
TreeSet<Integer> ts = new TreeSet<Integer>();
ts.add(12);
ts.add(8);
ts.add(15);
ts.add(13);
System.out.println(ts); //[8,12,13,15]
}
}
5、相关方法
Object first() 返回TreeSet集合的首个元素
Object last() 返回TreeSet集合的最后一个元素
Object lower(Object o) 返回TreeSet集合中小于给定元素的最大元素,如果没有返回null
Object floor(Object o) 返回TreeSet集合中小于或等于给定元素的最大元素,如果没有返回null
Object higher(Object o) 返回TreeSet集合中大于给定元素的最小元素,如果没有返回null
Object ceiling(Object o) 返回TreeSet集合中大于或等于给定元素的最小元素,如果没有返回null
Object pollFirst() 移除并返回集合的第一个元素
Object pollLast() 移除并返回集合的最后一个元素
6、TreeSet如何保证排序?
向TreeSet集合添加元素时,都会调用compareTo()方法进行比较排序,该方法是Comparable接口中定义的,因此要想对集合中的元素进行排序,就必须实现Comparable接口。
Java中大部分的类都实现了Comparable接口,并默认实现了接口中的CompareTo()方法,如Integer、Double和String等。
7、排序种类
7.1 自然排序
要求存储的元素类必须实现Comparable接口,并重写compareTo()方法。
public class Person implements Comparable<Person>{
private String name;
private int age;
public Person(){
super();
}
public Person(String name,int age)
{
super();
this.name = name;
this.age = age;
}
......//get/set方法
@Override
public int compareTo(Person p){
//按照年龄的降序排列
int result = p.age-this.age;
return result;
}
.....//toString方法
}
7.2 定制排序
要求自定义一个比较器,该比较器必须实现Comparator接口,并重写compare()方法,然后将该比较器作为参数传入集合的有参构造。
public class Demo12{
public static void main(String[] args){
TreeSet<Teacher> ts = new TreeSet<Teacher>(new Comparator<Teacher>() {
@Override
public int compare(Teacher t1,Teacher t2){
int result = t1.getAge() - t2.getAge();
return result;
}
});
}
}
Teacher t1 = new Teacher("张三",23);
Teacher t2 = new Teacher("里斯",24);
Teacher t3 = new Teacher("王五",25);
ts.add(t1);
ts.add(t2);
ts.add(t3);
十一、Map接口简介
1、说明
Map接口是一种双列集合,它的每个元素都包含一个键对象key和值对象Value,键和值对象之间存在一种对应关系,称为映射。
2、特点
Map中的映射关系是一对一的,一个键对象Key对应唯一一个值对象Value,其中键对象Key和值对象Value可以是任意数据类型,并且键对象Key不允许重复,这样在访问Map集合中的元素时,只要指定了Key,就能找到对应的Value。
十二、HashMap集合
1、说明
HashMap集合是Map接口的一个实现类,它用于存储键值映射关系,该集合的键和值允许为空,但键不能重复,且集合中的元素是无序的。
2、特点
HashMap底层是由哈希表结构组成的,其实就是"数组+链表"的组合体,数组是HashMap的主体结构,链表则主要是为了解决哈希值冲突而存在的分支结构。正因为这样特殊的存储结构。HashMap集合对于元素的增、删、改、查操作表现出的效率都比较高。
3、HashMap相关方法
3.1 HashMap集合存储元素的原理
依赖hashCode()方法计算哈希值,通过哈希值找到存储位置。
如果哈希值计算重复,则比较equals()方法,来比较键的内容是否相同。
如果equals方法返回的是true,会使用新值将老值替换。并且返回老值。
如果equals方法返回false,将后添加的元素放在之前元素的下列。
水平:数组结构
竖直:链表结构
3.2 相关代码
T put(Object key, Object value) //向Map集合中添加指定键值映射的元素
int size() //返回Map集合键值对映射的个数
Object get(Object key) //返回指定键所映射的值,如果此映射不包含该键的映射关系,则返回null
boolean containsKey(Object key) //查看Map 集合中是否存在指定的键对象key
boolean containsValue(Object value) //查看Map 集合中是否存在指定的值对象value
Object remove(Object key) //删除并返回Map 集合中指定键对象key 的键值映射元素
boolean remove(Object key,Object value) //删除Map 集合中键值映射同时匹配的元素(JDK8新方法)
void clear() //清空整个Map集合中的键值映射元素
String replace(Object key,Object value) //将Map集合中指定键对象Key所映射的值修改为value (JDK8新方法)
public class Demo13{
public static void main(String[] args){
//创建HashMap集合对象
HashMap<String, String> map = new HashMap<String, String>();
//T put(Object key, Object value) //向Map集合中添加指定键值映射的元素
map.put("hm001","张三");
map.put("hm002","李四");
map.put("hm003","王五");
map.put("hm004","赵六"); //键不能重复,使用新值将老值替换,并返回老值
//int size() //返回Map集合键值对映射的个数
System.out.println(map.size());
//Object get(Object key) //返回指定键所映射的值,如果此映射不包含该键的映射关系,则返回null
String value = map.get("hm001");
System.out.println(value);
//boolean containsKey(Object key) //查看Map 集合中是否存在指定的键对象key
boolean b = map.containsKey("hm002");
System.out.println(b);
//boolean containsValue(Object value) //查看Map 集合中是否存在指定的值对象value
b = map.containsValue("李四");
System.out.println(b);
//Object remove(Object key) //删除并返回Map 集合中指定键对象key 的键值映射元素
map.remove("hm003");
System.out.println(map);
//boolean remove(Object key,Object value) //删除Map 集合中键值映射同时匹配的元素(JDK8新方法)
map.remove("hm003","赵六");
System.out.println(map);
//void clear() //清空整个Map集合中的键值映射元素
map.clear();
//String replace(Object key,Object value) //将Map集合中指定键对象Key所映射的值修改为value (JDK8新方法)
map.replace("hm001","葛二蛋");
System.out.println(map);
}
}
十三、Map集合遍历
1、过程
(1)调用map集合的KeySet()方法,将所有的key保存到一个Set集合中。
(2)遍历Set集合,拿到每一个key。
(3)调用map集合的get()方法,通过键获取值。
2、集合遍历的方法
2.1 第一种方法 keySet()方法
public class Demo14{
public static void main(String[] args){
HashMap<String, String> hm = new HashMap<String, String>();
hm.put("hm001","张三");
hm.put("hm002","李四");
hm.put("hm003","王五");
//第一种方式:keySet()方法
Set<String> keys = hm.keySet();
for(String key: keys){
String value = hm.get(key);
System.out.println(Key + "=" + value);
}
}
2.2 第二种方法 entrySet()方法
public class Demo15{
public static void main(String[] args){
HashMap<String, String> hm = new HashMap<String, String>();
hm.put("hm001","张三");
hm.put("hm002","李四");
hm.put("hm003","王五");
//第二种方法 entrySet()方法
Set<Map.Entry<String, String>> entrys = hm.entrySet();
Iterator<Map.Entry<String, String>> it = entrys.iterator();
while(it.hasNext())
{
Map.Entry<String, String> entry = it.next();
String key = entry.getKey();
String value = entry.getValue();
System.out.println(Key + "=" + value);
}
}
2.3 第三种方法 forEach(BiConsumer); JDK8版本新增的遍历方法
public class Demo16{
public static void main(String[] args){
HashMap<String, String> hm = new HashMap<String, String>();
hm.put("hm001","张三");
hm.put("hm002","李四");
hm.put("hm003","王五");
//第三种方法 forEach(BiConsumer); JDK8版本新增的遍历方法
hm.forEach((String key,String value)->{System.out.println(key + "=" + value);});
}
2.4 第四种方法 values(); 获取map集合中所有的值,返回到一个Collection集合中。forEach(); 方法
public class Demo17{
public static void main(String[] args){
HashMap<String, String> hm = new HashMap<String, String>();
hm.put("hm001","张三");
hm.put("hm002","李四");
hm.put("hm003","王五");
//第四种方法 values(); 获取map集合中所有的值,返回到一个Collection集合中。forEach(); 方法
Collection<String> values = hm.values();
values.forEach((String value)->{System.out.println(value);});
}
十四、TreeMap集合
1、介绍
TreeMap集合是Map接口的另一个实现类,在TreeMap内部是通过二叉树的原理来保证键的唯一性,这与TreeSet集合存储的原理是一样,因此TreeMap中所有的键是按照某种顺序排列的。
2、说明
为了实现TreeMap元素排序,可以参考TreeSet集合排序方式,使用自然排序和定制排序
//TreeMap自然排序
public class Demo18{
public static void main(String[] args){
TreeMap<String, String> tm = new TreeMap<String, String>();
tm.put("tm001","张三");
tm.put("tm002","李四");
tm.put("tm003","王五");
System.out.println(tm);
}
//TreeMap定制排序
//按照年龄的升序排序
public class Demo19{
public static void main(String[] args){
TreeMap<String, String> tm = new TreeMap<String, String>(new Comparator<Teacher>(){
@Override
public int compare(Teacher t1, Teacher t2)
{
return t1.getAge() - t2.getAge();
}
});
tm.put("tm001","张三");
tm.put("tm002","李四");
tm.put("tm003","王五");
System.out.println(tm);
}
十五、Properties集合
1、介绍
Map接口还有一个实现类Hashtable, 它和HashMap十分相似,其中一个主要区别在于Hashtable是线程安全的。
2、说明
Hashtable类有一个子类Properties。Properties主要用来存储字符串类型的键和值,在实际开发中,经常使用Properties集合类来存取应用的配置项。
3、构造方法
Properties() 创建一个Properties集合对象
4、成员方法
String getProperty(String key) //通过键获取值
void load(InputStream inStream) //从流中读取文件
Object setProperty(String key,String value) //向集合中添加数据
void store(OutputStream out, String comments) //将集合中的数据通过输出流写出到文件中
5、实例一
public class Demo20{
pubclic class void main(String[] args)
{
//创建Properties集合对象
Properties prop = new Properties();
//向集合中添加数据
prop.setProperty("username","admin");
prop.setProperty("password","123456");
//获取集合中的数据
String username = prop.getProperty("username");
String password = prop.getProperty("password");
System.out.println(username + "===" + password);
}
}
6、实例二
创建一个config.properties配置文件
#update config
tel = 1888888888
username = admin;
password = 123456;
再创建一个class文件
public class Demo21{
public static void main(String[] args){
Properties prop = new Properties();
prop.load(new FileInputStream(""config.properties));
String username = prop.getProperty("username");
String password = prop.getProperty("password");
System.out.println(username);
System.out.println(password);
prop.setProperty("tel","1888888888");
prop.store(new FileOutputStream("config.properties"),"update config");
}
}
十六、泛型
集合中可以存储任意类型的对象元素,但是当把一个对象存入集合后,集合会“忘记” 这个对象的类型,将该对象从集合中取出时,这个对象的编译类型就统一变成了Object类型。
也就是说,在程序中无法确定一个集合中的元素到底是什么类型,那么在取出元素时,如果进行强制类型转换就很容易出错。
1、实例
public class Demo22{
public static void main(String[] args){
//未进行泛型约束的,存入后默认为object,不好遍历循环
ArrayList list = new ArrayList();
list.add(100);
list.add(true);
list.add("abc");
//泛型约束的
ArrayList<String> list2 = new ArrayList<>();
list2.add("abc");
list2.add("bcd");
for(String s : list2){
System.out.println(s);
}
}
}
十七、Collections工具类
1、说明
Java提供了一个工具类专门用来操作集合,这个类就是Collections, 它位于java.util包中
Collections类中提供了大量的静态方法用于对集合中元素进行排序、查找和修改等操作。
2、相关方法
static boolean addAll(Collection<? super T> c,T… elements) //将所有指定元素添加到指定集合C中
static void reverse(List list) //反转指定List集合中元素的顺序
static void shuffle(List list) //对List集合中的元素进行随机排序
static void sort(List list) //根据元素的自然顺序对List集合中的元素进行排序
static void swap(List list,int i,int j) //指定List集合中角标i处的元素和j处元素进行交换
static int binarySearch(List list,Object key) //使用二分法搜索指定对象在List集合中的索引,查找的List集合中的元素必须是有序的
static Object max(Collection col) //根据元素的自然顺序,返回给定集合中最大的元素
static Object min(Collection col) //根据元素的自然顺序,返回给定集合中最小的元素
static boolean replaceAll(List list,Object oldVal,Object newVal) //用一个新值newVal替换List集合中所有的旧值oldVal
3、相关代码
public class Demo23{
public static void main(String[] args){
ArrayList<String> list = new ArrayList<String>();
//static <T> boolean addAll(Collection<? super T> c,T... elements) //将所有指定元素添加到指定集合C中
Collections.addAll(list,"a","b","c"); //[a,b,c,d]
//static void reverse(List list) //反转指定List集合中元素的顺序
Collections.reverse(list);
System.out.println(list); //[d,c,b,a]
//static void shuffle(List list) //对List集合中的元素进行随机排序
Collections.shuffle(list);
System.out.println(list); //[a,c,b,d]
//static void sort(List list) //根据元素的自然顺序对List集合中的元素进行排序
Collections.sort(list);
System.out.println(list); //[a,b,c,d]
//static void swap(List list,int i,int j) //指定List集合中角标i处的元素和j处元素进行交换
Collections.swap(list,2,3);
System.out.println(list); //[a,b,d,c]
//static int binarySearch(List list,Object key) //使用二分法搜索指定对象在List集合中的索引,查找的List集合中的元素必须是有序的
int index = Collections.binarySearch(list, "b");
System.out.println(index);
//static Object max(Collection col) //根据元素的自然顺序,返回给定集合中最大的元素
String max = Collections.max(list);
System.out.println(max);
//static Object min(Collection col) //根据元素的自然顺序,返回给定集合中最小的元素
String min = Collections.min(list);
System.out.println(min);
//static boolean replaceAll(List list,Object oldVal,Object newVal) //用一个新值newVal替换List集合中所有的旧值oldVal
Collections.replaceAll(list, "b","f");
System.out.println(list);
}
}
十八、Arrays数组工具类
1、相关方法
void sort(); //对数组排序
String toString(); //打印数组
int binarySearch(Object[] a,Object key); //使用二分查找法获取指定元素在数组中出现的索引位置
int[] copyOfRange(int[] original, int from, int to); //复制数组元素到一个新数组中
void fill(Object[] a,Object val); //使用传入元素替换数组中所有的元素
2、相关代码
public class Demo24{
public static void main(String[] args){
int[] arr = {10,30,20,50,40,60}
//void sort(); //对数组排序
Arrays.sort(arr);
//String toString(); //打印数组
System.out.println(Arrays.toString(arr));
//int binarySearch(Object[] a,Object key); //使用二分查找法获取指定元素在数组中出现的索引位置
int index = Arrays.binarySearch(arr,50);
System.out.println(index);
//int[] copyOfRange(int[] original, int from, int to); //复制数组元素到一个新数组中
int[] arr2 = Arrays.copyOfRange(arr,1 ,4);
System.out.println(Arrays.toString(arr2));
//void fill(Object[] a,Object val); //使用传入元素替换数组中所有的元素
Arrays.fill(arr2,88);
System.out.println(Arrays.toString(arr2)); //[88, 88, 88]
}
}
十九、聚合操作
1、介绍
由于原始操作方法(普通循环遍历出每一个元素,然后穿插一些if条件语句选择性的对元素进行查找、过滤、修改等操作)可行,但代码量较大并且执行效率较低,因此JDK8中新增了聚合操作,可以进一步简化集合、数组中元素的查找、过滤、转换等
2、定义
JDK8中新增了一个Stream接口,该接口可以将集合、数组中的元素转换为Stream流的形式,并结合Lambda表达式的优势来进一步简化集合、数组中元素的查找、过滤、转换等操作,这就是聚合操作。
3、操作步骤
(1)将原始集合或者数组对象转换为Stream流对象
(2)对Stream流对象中的元素进行一系列的过滤、查找等中间操作,然后返回一个Stream流对象
(3)对Stream流进行遍历、统计、收集等终结操作,获取想要的结果。
4、实例
/*
* 终结方法:方法的返回值类型是void,就不能再调用其他的方法了
* 非终结方法:方法的返回值类型是Stream流。还可以继续调用其他方法
*/
public class Demo1{
public static void main(String[] args){
ArrayList<String> list = new ArrayList<String>();
list.add("张三");
list.add("李四");
list.add("张小明");
list.add("王五");
list.add("赵六");
list.stream().filter((String s)->{return s.startsWith("张");}).limit(2).forEach((String s)->{System.out.println(s);});
}
}
二十、创建Stream流对象
1、创建方法
(1)所有的Collection集合都可以使用stream()静态方法获取Stream流对象
(2)Stream接口的of()静态方法可以获取基本类型包装类数组、引用类型数组和单个元素的Stream流对象
(3)Arrays工具类的stream()静态方法也可以获取数组元素的Stream流对象
2、实例
2.1 获取Stream流的方式
(1)通过单列集合的静态方法:stream()获取Stream流对象
(2)通过Stream接口静态方法:of(数组)获取Stream流对象
(3)通过Arrays工具类静态方法:stream(数组)获取Stream流对象
public class Demo25{
public static void main(String[] args){
Integer[] arr = {10,20,30,40,50};
Stream<Integer> s1 = Arrays.stream(arr);
s1.forEach((Integer i)->{System.out.println(i);});
Stream<String> s2 = Stream.of("aaa","bbb","ccc");
s2.forEach((String s)->{System.out.println(s);});
ArrayList<String> list = new ArrayList<String>();
list.add("张三");
list.add("李四");
list.add("王五");
Stream<String> s3 = list.stream();
s3.forEach((String s)->{System.out.println(s);});
HashMap<String, String> map = new HashMap<String, String>();
map.put("hm001","张三");
map.put("hm002","李四");
map.put("hm003","王五");
Set<String> keys = map.keySet();
Stream<String> s4 = keys.stream();
}
}
二十一、Stream流的常用方法
1、Stream流常用操作
Stream filter(Predicate<? super T> predicate) //将指定流对象中的元素进行过滤,并返回一个子流对象
Stream map(Function<? super T,? extends R> mapper) //将流中的元素按规则映射到另一个流中
Stream distinct() //删除流中重复的元素
Stream sorted() //将流中的元素按自然顺序排序
Stream limit(long maxSize) //截取流中元素的长度
Stream skip(long n) //丢弃流中前n个元素
static Stream concat(Stream<? extends T> a.Stream<? extends T> b) //将两个流对象合并为一个流
long count() 统计流中元素的个数
R collect(Collector<? super T, A, R> collector) //将流中的元素收集到一个容器中(如集合)
Object[] toArray() //将流中的元素收集到一个数组中
void forEach(Consumer<? supper T> action) //将流中的元素进行遍历
public class Demo26{
public static void main(String[] args){
ArrayList<String> list = new ArrayList<String>();
list.add("张三");
list.add("李四");
list.add("张小明");
list.add("张果老");
//通过流对象遍历集合元素
Stream<String> s1 = list.stream();
s1.forEach((String s)->{System.out.println(s);});
System.out.println("=====================================");
//过滤:获取集合中以张为开头并且名字长度大于2
Stream<String> s2 = list.stream();
s2.filter((String s)->{return s.startsWith("张")&&s.length()>2;}).forEach(s->System.out.println(s));
System.out.println("=====================================");
//筛选+排序:获取集合中以a为开头。将字符串转成大写并排序
Stream<String> s3 = list.stream();
s3.filter(s->s.startsWith("a")).map(s->s.toUpperCase()).sorted().forEach(s->System.out.println(s));
//跳过+截取:跳过前2个字符串,只要3-6个(只要四个字符串)
Stream<String> s4 = list.stream();
s4.skip(2).limit(4).forEach(s->System.out.println(s));
//将流对象的元素转成一个集合:获取集合中以张为开头的字符串。返回一个新的集合中
Stream<String> s5 = list.stream();
List<String> list2 = s5.filter(s->s.startsWith("张")).collect(Collectors.toList());
System.out.println(list2);
}
}
二十二、Parallel Stream(并行流)
1、种类
1.1 串行流
就是将源数据转换为一个流对象,然后在单线程下执行聚合操作的流。(也就是单一管道流)
1.2 并行流
就是将源数据分为多个子流对象进行多线程操作(也就是多个管道流)然后将处理的结果再汇总为一个流对象。
2、Parallel Stream(并行流)
2.1 原理
Stream并行流底层会将源数据拆解为多个流对象在多个线程中并行执行,这依赖于JDK7中新增的fork/join框架,该框架解决了应用程序并行计算的能力,但是单独使用这个框架,必须指定源数据如何进行详细拆分,而JDK8中的聚合操作,在fork/join框架的基础上进行组合解决了这一麻烦。
2.2 注意
使用Stream并行流在一定程度上可以提升程序的执行效率,但是在多线程执行就会出现线程安全这个大问题,所以为了能够在聚合操作中使用Stream并行流,前提是要执行操作的源数据在并行执行过程中不会被修改。
3、创建
3.1 说明
创建Stream流对象时,除非有特别声明,否则默认创建的都是串行流。
3.2 创建方式
(1)通过Collection集合接口的parallelStream()方法直接将集合类型的源数据转变为Stream并行流
(2)通过BaseStream接口的parallel()方法将Stream串行流转变为Stream并行流。
4、代码
public class Demo27{
public static void main(String[] args){
ArrayList<String> list = new ArrayList<String>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
//获取到的是串行流
Stream<String> s1 = list.stream();
Stream<String> s2 = s1.parallel();
//获取并行流-通过集合的parallelStream()
Stream<String> s3 = list.parallelStream();
System.out.println(s1.isParallel());
System.out.println(s2.isParallel());
System.out.println(s3.isParallel());
}
}
版权归原作者 熊凯瑞 所有, 如有侵权,请联系我们删除。