Java集合框架
- Collection:
- List:允许重复的有序集合,能精确控制每个元素的插入位置,可使用索引来访问List中的元素,ArrayList主要是用数组来存储元素,LinkedList主要是用链表来存储元素,当随机访问元素操作多的时候,优先使用ArrayList,当增加与删除操作多的时候,优先使用LinkedList(List允许加入null值)
- Set:存储不重复的元素
- SortedSet:继承Set接口,内部元素按照一定的规则排序(自然排序或者Comparator指定的排序规则)
- NavigableSet:是SortedSet的子接口,扩展了一些导航的方法,可以用于更精准的定位。
- HashSet:无序,实现了类Set接口,是使用对象的哈希值来决定元素的存放位置,调用对象的hashCode可以获取哈希值
- LinkedHashSet:有序,继承HashSet,使用双向链表维护元素的顺序
- TreeSet:有序,扩展自AbstractSet,并实现了NavigableSet
- Queue:先进先出的数据结构,(Queue不允许加入null值)
- Deque:继承Queue的双端队列,支持在两端插入和删除元素,可以用LinkedList实现队列(实现了Deque接口)
- PriorityQueue:继承Queue,优先队列,优先队列中元素被赋予优先级,拥有高优先级的先被删除,对内部元素的排序不会体现在遍历上
- Map:键值对映射,一个Map中不能有相同的key,每个key只能映射一个value
- SortedMap继承Map接口,key按照升序排列
- NavigableMap:是SortedMap的子接口
- HashMap:
- LinkedHashMap:继承自HashMap
- TreeMap:继承自AbstractMap,是NavigableMap的实现类
Map的遍历
- 使用keyset
- 使用entrySet
- 使用forEach
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapTraverse {
public static void main(String[] args) {
Map<Integer,Integer> map = new HashMap<>();
map.put(1, 2);
map.put(3, 4);
map.put(5, 6);
//1、使用keyset方法
Set<Integer> set = map.keySet();
set.forEach(k-> System.out.println(k+","+ map.get(k)));
//2、使用Map.Entry方法
Set<Map.Entry<Integer, Integer>> set2 = map.entrySet();
set2.forEach(e->System.out.println(e.getKey()+","+e.getValue()));
//3、使用foreach方法
map.forEach((k,v)->System.out.println(k+","+v));
}
}
集合的遍历
- 使用iterator接口(原始方法)
- 使用iterator接口(新增方法)
- 使用增强型for循环
- 使用forEach方法
- 使用聚合操作
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Traverse {
public static void main(String[] args) {
Collection<Integer> c = new ArrayList<>();
for (int i = 0; i < 5; i++) {
c.add(i);
// c.add(Integer.valueOf(i));
}
//1、 使用Iterator原始方法,获得Iterator,初始指针为第一个元素之前
Iterator<Integer> i = c.iterator();
// 判断是否含有下一个元素,如果存在下一个元素,返回True,否则返回False
while (i.hasNext()) {
// 返回下一个元素,同时,向前移动指针位置
Integer item = i.next();
// System.out.println(item);
// 在使用迭代器Iterator遍历集合元素时,如果通过集合元素修改元素,
// 就会发生异常(ConcurrentModificationException异常)
// c.remove(item)
// 如果想要安全的删除元素,可以使用Iterator提供的remove方法。
// i.remove();
}
//2、 使用Iterator新增的方法
i = c.iterator();
//i.forEachRemaining(t->System.out.println(t));
// i.forEachRemaining(System.out::println);
//3、使用foreach方法
for(Integer item:c){
// System.out.println(item);
}
//4、使用forEach方法遍历
// c.forEach(System.out::println);
//5、使用聚合操作方法
c.stream().forEach(System.out::println);
}
}
Iterator接口
使用Iterator接口时,在使用迭代器Iterator遍历集合元素时,如果通过集合元素修改元素,就会发生异常(ConcurrentModificationException异常),如果想要安全的删除元素,可以使用Iterator提供的remove方法。
聚合操作
流是一组元素的序列,集合对象可以通过相关方法获得流。通过集合对象的流,就可以在流的基础上对集合元素进行相关的操作,如过滤、映射、迭代等,该操作也称为流操作,也称为聚合操作。
流管道为一系列顺序的聚合操作,管道由数据源(数组、集合、IO通道等),中间操作(零个或多个)与终端操作(一个)组成。
聚合操作分为中间操作和终端操作,聚合操纵的中间操作会产生一个新的流,供后续中间操作或终端操作使用,而终端操作不会再产生流。中间操作是惰性的,这样才能在一定程度上提高性能,流只有在终端操作时才开始执行,也就是说仅仅调用流的中间操作,其实并没有真正开始流的源的遍历。一个流只能有一个终止操作,它必定是流的最后一个操作。只有调用了流的终止操作,流的源的元素才会真正的开始遍历,并且会生成一个结果返回或者产生一个副作用。中间操作分为有状态操纵和无状态操作,无状态中间操作是指元素的处理不受前面元素的影响,而有状态的中间操作必须等到所有元素处理之后才知道最终结果。并且一旦执行终端操作,则整个流都被消费掉,不可再次使用。
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collector;
import java.util.stream.Collectors;
/*
*聚合操作:
**/
public class AgOp {
public static void main(String[] args) {
Collection<Integer> c = new ArrayList<>();
for (int i=0;i<10;i++){
c.add(i);
}
//c.stream().filter(e->e>5).forEach(System.out::println);
Collection<Student> c1 = new ArrayList<>();
for (int i=0;i<10;i++){
c1.add(new Student(i%4, "名字"+i));
}
//c1.stream().map(s-> new Teacher(s.getId(), s.getName())).forEach(System.out::println);
//c1.stream().map(Student::getId).forEach(System.out::println);
//System.out.println(c1.stream().mapToInt(Student::getId).sum());
//c1.stream().mapToInt(Student::getId).distinct().forEach(System.out::println);
//c1.stream().distinct().forEach(System.out::println);
//c1.stream().distinct().sorted((s1,s2)->(Integer.valueOf(s2.getId()))
// .compareTo(s1.getId())).forEach(System.out::println);
//c1.stream().mapToInt(Student::getId).distinct().peek(System.out::println).forEach(System.out::println);
// c.stream().limit(5).forEach(System.out::println);
//c.stream().skip(3).forEach(System.out::println);
// System.out.println(c1.stream().mapToInt(Student::getId).max().getAsInt());
// System.out.println(c1.stream().mapToInt(Student::getId).min().getAsInt());
// System.out.println(c1.stream().mapToDouble(Student::getId).average().getAsDouble());
// System.out.println(c1.stream().mapToInt(Student::getId).sum());
// System.out.println(c1.stream().mapToInt(Student::getId).count());
// int sum = c1.stream().mapToInt(Student::getId).reduce(Integer::sum).getAsInt();
// System.out.println(sum);
// int max = c1.stream().mapToInt(Student::getId).reduce(Math::max).getAsInt();
// System.out.println(max);
//
// int min = c1.stream().mapToInt(Student::getId).reduce(Math::min).getAsInt();
// System.out.println(min);
// String jion = c1.stream().map(Student::getName).reduce(String::concat).get();
// System.out.println(jion);
List<Student> list = c1.stream().filter(s->s.getId()<3).collect(Collectors.toList());
list.forEach(System.out::println);
StringBuilder s =c1.stream().map(Student::getName)
.collect(StringBuilder::new,StringBuilder::append,StringBuilder::append);
System.out.println(s);
}
}
class Teacher{
private int id;
private String name;
public Teacher(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "Teacher[id="+id+",name="+name+"]";
}
}
class Student{
private int id;
private String name;
public Student(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "Student[id="+id+",name="+name+"]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
- map/flatMap 映射:map操作是讲流中的元素映射成另外一种元素,接受一个Function类型的参数,是一个中间操作
- filter 过滤:filter是对流中的元素进行过滤操作,会接受一个Predicate类型的参数,是一个中间操作。只要是不满足这个predicate的,也就是说predicate.test()返回false的元素会被过滤掉
- distinct 去重:distinct操作是对流中的元素进行去重,是一个中间操作
- sorted 排序:orted操作是对流中的元素按照进行排序,是一个中间操作。不带参数的是按照自然顺序进行排序。带参数的会传一个Comparator类型的参数,作为比较规则
- limit:imit获取流中前n个元素返回。是一个中间操作。另外这个是一个短路操作(short-circuiting)。也就是说流中的元素遍历到了第n个过后,后面的元素就不在进行遍历了
- peek:生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数(Consumer实例),新Stream每个元素被消费的时候都会执行给定的消费函数
- skip:skip操作是跳过流中的前n个元素。是一个中间操作
- forEach:forEach操作是流中的元素遍历并且执行一个action。这是一个终止操作
- toArray:将流转换为一个数组。是一个终止操作
- reduce:reduce汇聚操作,是一个终止操作。这个方法的主要作用是把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce
- min、max:求最大值最小值,是一个终止操作
- count:计算流中元素的个数。是一个终止操作
- collect 收集:对流中元素执行一个可变汇聚操作。是一个终止操作。比如:将流中的元素放入到一个List集合当中,将流中的元素进行分组、分区,求和等等操作
聚合操作和迭代器的区别:
- 聚合操作从流中处理数据,不改变底层的数据源,而迭代器则对集合进行操作,会改变集合
- 聚合操作使用内部迭代的方法,而迭代器使用外部迭代进行处理
- 聚合操作(内部迭代)可以根据需要并行处理数据,而迭代器只能顺序执行