第五节 Java 集合
- 1. 集合概述
- 1.1 数组与集合之间的区别
- 1.2 集合的分类
- 2. Collection接口
- 3. List接口
- 3.1 ArrayList 集合
- 3.2 LinkedList 集合
- 3.3 Vector集合
- 4. Collection 集合遍历
- 4.1 通过Iterator进遍历
- 4.2 通过增强for来进行遍历
- 4.3 通过集合的forEach(Consumer action)方法来遍历
- 4.4 通过迭代器的forEachRemaining(Consumer action)方法来进行遍历
- 4.5 通过for循环来进行遍历
- 5. Set 接口
- 5.1 HashSet 集合
- 5.2 TreeSet 集合
- 6. Map 接口
- 6.1 HashMap 集合
- 6.2 Map 集合的遍历
- 6.3 LinkedHashMap 集合
- 6.4 TreeMap 集合
- 6.5 Properties 集合
- 7. 泛型
- 8. 常用工具类
- 8.1 Collections 工具类
- 8.2 Arrays 工具类
- 9. 聚合操作
- 9.1 创建Stream流对象的几种方式
- 9.2 Stream流常用方法
- 9.3 Parallel Stream(并行流)
1. 集合概述
1.1 数组与集合之间的区别
集合主要是用来解决数组的一些缺陷,比如数组的长度不能够自动的根据内容的添加去自动的去增加长度,一旦数组的长度定下来就不会变了,这样有时候会发现我们定义的长度不够,或者定义的长度过长导致内存利用率降低,而集合是一个长度可变的容器,他会自动的根据我们的添加和删除去自动的给我们增加或添加空间。但是,集合的速度不如数组的快(在有些时候),但又各有优点。因此在选择的时候可以根据需要去进行选择。
1.2 集合的分类
这些集合都位于java.util包中。按存储结构我们可以分为两类单列集合Collection和双列集合Map。
(1)对于单列集合:Collection集合有两个重要的子接口,分别是List和Set。List集合的特点就是元素有序(存入顺序和取出顺序一致),可重复。对于Set集合元素无序且不可重复。List的主要实现类有ArrayList和LinkedList;Set主要的实现类有HashSet和TreeSet。
(2)对于双列集合:Map用于存储具有键值映射关系的元素,主要的实现类有HashMap和TreeMap。
虚框是接口,实框是实现类。
2. Collection接口
这里面的方法是单列集合的通用方法,主要方法有如下:
方法声明 | 功能描述 |
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中的元素 |
Iterator iterator() | 返回该集合的元素上进行迭代的迭代器 |
int size() | 获取该集合元素个数 |
Stream<E> stream() | 将集合源转换为有序元素的流对象 |
3. List接口
List接口常用方法:
方法声明 | 功能描述 |
void add(int index,Object element) | 将元素element插入集合指定索引 |
boolean addAll(int index,Collention c) | 将集合c包含的所有元素插入指定索引位置处 |
Object get(int index) | 返回指定索引处的元素 |
Object remove(int index) | 删除索引处的元素 |
Object set(int index,Object element) | 将索引处元素替换成element,并返回被替换的元素 |
int indexOf(Object o) | 返回对象o在List集合首次出现的索引 |
int lastIndexOf(Object o) | 返回对象o在List集合最后一次出现位置处的索引 |
List subList(int fromIndex,int toIndex) | 返回从fromIndex到toIndex(不包括)的List的子集 |
Object[ ] toArray() | 将集合元素转换为数组 |
default void sort(Comparator<? super E> c) | 根据指定的比较器规则对集合元素排序 |
3.1 ArrayList 集合
底层是由数组实现的,在增加或删除指定位置元素时效率比较低,但是在进行查询的时候比较快,它封装了一个变长的数组,当存入元素超过数组长度,ArrayList会在内存中分配一个更大的数组来存储这些元素。
3.2 LinkedList 集合
LinkedList集合它的底层是由双向循环链表实现的。因此在进行增删的时候效率比较高,但是查询效率不高。因此在选择时我们要根据我们要对数组进行怎么样的操来进行选择。
在LinkedList集合中有一些特有的方法:、
方法声明 | 功能描述 |
boolean add(int index,Object element) | 将元素插入指定位置 |
void addFirst(Object o) | 在集合开头插入元素 |
void addLast(Object o) | 在集合结尾添加元素 |
Object getFirst() | 返回集合第一个元素 |
Object getLast() | 返回集合中的最后一个元素 |
Object removeFirst() | 移除并返回集合中的第一个集合 |
Object removeLast() | 移除并返回集合中的最后一个集合 |
boolean offer(Object o) | 将指定元素添加到集合结尾 |
boolean offerFirst(Object o) | 将指定元素添加到集合开头 |
boolean offerLast(Object o) | 将指定元素添加到集合的结尾 |
Object peek() | 获取集合第一个元素 |
Object peekFirst() | 获取集合第一个元素 |
Object peekLast() | 获取集合最后一个元素 |
Object poll() | 移除并返回集合的第一个元素 |
Object pollFirst() | 移除并返回集合的第一个元素 |
Object pollLast() | 移除并返回集合最后一个元素 |
Object push(Object o) | 将指定元素添加到集合开头 |
Object pop() | 移除并返回集合的第一个元素 |
3.3 Vector集合
这是相当于老版本ArrayList集合,不过它加了很多的同步,所以它相对的比较的安全。
4. Collection 集合遍历
4.1 通过Iterator进遍历
方式如下:
public class IteratorDemo {
public static void main(String[] args) {
ArrayList<String> textArray=new ArrayList<String>();
textArray.add("iteratored1");
textArray.add("iteratored2");
Iterator iterator=textArray.iterator();
while(iterator.hasNext()){
String text= (String) iterator.next();
System.out.println(text);
}
}
}
结果如下:
但在这里遍历时不能对元素进行删除和添加操作,否则它的指针找不到对应位置会报错的。就好比,Iterator已经记好了它要遍历的每个元素对应的村粗空间,但是这时,你对里面的元素删除了,这样他指向下一个指针的时候这个空间可能就会在内存中显示空闲,这样就会报错。
这里有以下两种解决办法:
(1)如果从业务逻辑上我们只是单单删除某个元素然后跳出不再进行迭代是可以的,比如我们用,if(“iteratored2”.equals(text)){textArray.remove(text);break;}
(2)我们不通过集合的remove去删除,我们 通过迭代器自带的remove()方法来进行删除,比如我们在循环内部这样使用,if(“iteratored2”.equals(text)){iterator.remove();}
4.2 通过增强for来进行遍历
语法格式如下:
for(容器中元素类型 临时变量:容器变量){执行语句}
具体用法如下:
public class ForDemo {
public static void main(String[] args) {
ArrayList<String> array=new ArrayList<String>();
array.add("test1");
array.add("test2");
for(String obj:array){
System.out.println(obj);
}
}
}
结果如下:
这种方法比较简洁,但是也有它的一定局限性,这种方法只能对集合元素进行访问不能对其中的元素进行修改。
比如我们想将String[ ] strs={“aaa”,“bbb”,“ccc”};里面的所有元素修改成ddd,我们不能通过for(String str :strs){str=“ddd”}的方法来进行,因为这只是将临时变量str赋值了一个ddd,并没有对strs进行修改。
4.3 通过集合的forEach(Consumer action)方法来遍历
这是JDK 8之后才有的方法,这个方法需要的参数是一个函数式接口。
具体的使用方法如下:
public class ForEachDemo {
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<String>();
list.add("秀儿");
list.add("是你嘛");
list.forEach(str-> System.out.println("迭代集合元素:"+str));
}
}
结果如下图:
4.4 通过迭代器的forEachRemaining(Consumer action)方法来进行遍历
使用方法如下:
public class ForEachRemainingDemo {
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<String>();
list.add("通过迭代器的forEachRemaining方法来进行遍历");
list.add("遍历完了");
//将集合转换成迭代器对象
Iterator it=list.iterator();
it.forEachRemaining(str-> System.out.println(str));
}
}
结果如下图:
4.5 通过for循环来进行遍历
使用方法如下:
public class Forxunhuan {
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<String>();
list.add("forxunhuan");
list.add("bianli");
for (int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
}
}
结果如下图:
5. Set 接口
Set接口主要的实现类为:HashSet,TreeSet,其中HashSet根据对象的哈希值来确定元素在集合中存储的位置,所以它比较的容易查找和存取,TreeSet是通过二叉树的方式来进行元素的存储,它可以实现对集合中的元素进行排序。
5.1 HashSet 集合
当我们向HashSet集合中添加一个元素时,首先会调用该元素的hashCode()方法来确定元素的存储位置,然后再调用对象的equals()方法来确保这个位置没有重复元素。
注意:为了保证我们的HashSet集合可以正常的工作,当我们存入的是我们自定义的对象时,我们需要重写hashCode()方法和equals()方法,如果不是自定义的对象,他们的hashCode()和equals()方法都已经被重新二过了。
例如如下:
public class Student {
String id;
String name;
public Student(String id,String name){
this.id=id;
this.name=name;
}
//重写toString()方法
public String toString(){
return id+":"+name;
}
//重写hashCode()方法
public int hashCode(){
return id.hashCode();
}
//重写equals()方法
public boolean equals(Object obj){
if(this==obj){
return true;
}
if(!(obj instanceof Student)){
return false;
}
Student stu=(Student) obj;
boolean b=this.id.equals(stu.id);
return b;
}
}
public class Example01 {
public static void main(String[] args) {
HashSet hs=new HashSet();
Student stu1=new Student("01","san");
Student stu2=new Student("02","si");
hs.add(stu1);
hs.add(stu2);
System.out.println(hs);
}
}
结果如下:
5.2 TreeSet 集合
内部采用平衡二叉树来存储元素,这样可以保证TreeSet集合中没有重复的元素,并且对元素进行排序。所谓二叉树就是每个节点最多有两个子节点的有序树,每个节点的左边叫左子树,右边叫右子树,其中左子树小于它的根节点,右子树大于它的根节点。
TreeSet集合中一些特有方法如下:
public class TreeSetDemo {
public static void main(String[] args) {
//创建TreeSet集合
TreeSet ts=new TreeSet();
ts.add(3);
ts.add(5);
ts.add(11);
ts.add(8);
System.out.println("创建的TreeSet集合为:"+ts);
//获得集合中的首尾元素
System.out.println("集合首元素为:"+ts.first());
System.out.println("集合末尾元素为:"+ts.last());
//比较并获取元素
System.out.println("lower()方法,返回小于5的最大元素:"+ts.lower(5));
System.out.println("floor()方法,返回小于或等于5的最大元素:"+ts.floor(5));
System.out.println("higher()方法,返回大于5的最小元素:"+ts.higher(5));
System.out.println("ceiling()方法,返回大于或等于5的最小元素:"+ts.ceiling(5));
//移除并返回
System.out.println("移除并返回第一个元素:"+ts.pollFirst());
System.out.println("移除并返回最后一个元素:"+ts.pollLast());
}
当我们存入元素的时候首先会和根节点进行比较如果小于根节点,就和根节点左边的继续进行比较,如果大于根节点就和根节点右边的进行比较,以此类推一直比较到最后一个节点如果没有重复的,小于最后一个节点就放最后一个节点的左边,大于了就放最后一个节点的右边。在这里我们一般的对象都重写了Comparable里面的compareTo()方法,当我们存入的时候就会调用这个方法进行比较,但是我们在开发中可能会存入一些我们自定义的对象,这时候我们就需要重新制定排序规则。为了解决这个问题Java提供了两种方法
(1)自然排序
这里要求向TreeSet集合中存储的元素所在的类必须实现Comparable接口,并重写compareTo()方法,然后TreeSet集合就会对该类型元素使用compareTo()方法进行比较,并默认进行升序。
使用如下:
public class Teacher implements Comparable{
String name;
int age;
public Teacher(String name,int age){
this.name=name;
this.age=age;
}
public String toString(){
return name+":"+age;
}
//重写CompareTo()方法
public int compareTo(Object obj){
Teacher s=(Teacher) obj;
//按照年龄来进行升序
if (this.age-s.age>0){//将this.age和s.age互换就变成降序
return 1;
}
if(this.age-s.age==0){
return this.name.compareTo(s.name);//如果年龄相同,我们就用name来进行比较
}
return -1;
}
}
public class ComparableDemo {
public static void main(String[] args) {
TreeSet ts=new TreeSet();
ts.add(new Teacher("Jack",19));
ts.add(new Teacher("Rose",18));
ts.add(new Teacher("Tom",19));
ts.add(new Teacher("Rose",18));
System.out.println(ts);
}
}
结果如下:
(2)定制排序
用来当我们不想按照定义的compareTo()方法进行排序,比如我们希望可以按照字符串的长度,而不是英文字母顺序来进行排序,我们可以通过在创建TreeSet集合的时候就定义一个比较器往构造里面传入自定义的比较器来进行定制排序。
例如:
public class MyComparator implements Comparator {
@Override
public int compare(Object obj1, Object obj2) {//定制排序
String s1=(String)obj1;
String s2=(String)obj2;
int temp=s1.length()-s2.length();
return temp;
}
}
public class ComparatorDemo {
public static void main(String[] args) {
TreeSet ts=new TreeSet(new MyComparator());
ts.add("Java");
ts.add("Python");
ts.add("C++");
System.out.println(ts);
}
}
结果如下:
从上面的程序可以看出,我们需要写排序,根据某个值,因此我们在向TreeSet里面存入数据的时候我们要保证是同一种数据类型,不然会报错,所以这里就用到了我们的泛型。
6. Map 接口
在Map里面键是唯一的,键值对一一对应。
Map常用的方法:
方法说明 | 功能描述 |
void put(Object key,Object value) | 向Map集合中添加指定键值映射元素 |
int size() | 返回集合中键值对的个数 |
Object get(Object key) | 返回指定键所映射的值,若没有返回null |
Object getOrDefault(Object key,Object DefaultValue) | 返回指定键对应的值,不存在默认返回default。 |
boolean containsKey(Object key) | 判断集合中是否存在这个键 |
boolean containsValue(Object value) | 判断集合中是否存在这个值 |
Object remove(Object key) | 移除指定键的键值对。 |
void clear() | 清空整个Map集合中的键值映射元素 |
Set keySet() | 以Set集合的形式返回Map集合中所有的key对象 |
Collection values() | 以Collection集合的形式返回Map集合中所有值对象 |
Set<Map.Entry<Key,Value>> entrySet() | 将Map集合转换为存储类型为Map的Set集合 |
void forEach(BiConsumer action) | 通过传入一个函数式接口,对Map集合元素进行遍历 |
Object putIfAbsent(Object key,Object value) | 向Map集合中添加指定键值映射,如果已经存在就不再添加了,返回已存在的Value值 |
boolean remove(Object key,Object value) | 删除键值对同时匹配的元素 |
boolean replace(Object key,Object value) | 将Map集合中指定键对象所映射的值改为value |
6.1 HashMap 集合
HashMap是Map的一个实现类,键和值允许为空,但是键不能重复,且集合中的元素是无序的。它的底层是由数组+链表来实现的。链表主要是用来解决哈希冲突的。结构上水平方向数组的长度称为HashMap的容量,竖直方向每个元素位置对应的链表结构称为一个桶,每个桶的位置在集合中都有对应的桶值,当我们向集合中添加元素时,首先会调用键对象的hash(k)方法寻找到该元素要存储的位置,如果这个位置为空,那么就直接放到集合内,如果这个位置不为空,那么就需要来比较已经存在的k与要添加进去的元素的k值是否相同,如果相同就将原来k对应的值修改为新的k对应的值,如果不相同,就会在这个桶的链表结构头部新增一个节点来插入新元素对象。
HashMap中桶数量分配策略:
在我们创建HashMap之后,会默认集合的容量capacity为16,加载因子loadFactor为0.75,此时改集合桶的阈值就为12,当添加的元素超过12之后,HashMap就会默认增加一倍的桶数量,如果开发中想节省一点空间可以通过它的构造方法来设置桶初始容量和加载因子。new HashMap(int initialCapacity,float loadFactor)
6.2 Map 集合的遍历
(1)通过迭代器遍历Map
第一种:使用如下:
public class MapDemo01 {
public static void main(String[] args) {
Map map=new HashMap();
map.put("1","Jack");
map.put("2","Rose");
map.put("3","Lucy");
System.out.println(map);
Set keySet=map.keySet();
Iterator it=keySet.iterator();
while(it.hasNext()){
String key=(String)it.next();
String value=(String)map.get(key);
System.out.println(key+":"+value);
}
}
}
结果如下图:
第二种:通过entrySet()方法获取
public class MapDemo03 {
public static void main(String[] args) {
Map map=new HashMap();
map.put("1","Jack");
map.put("2","Rose");
map.put("3","Lucy");
System.out.println(map);
Set entrySet=map.entrySet();
Iterator it=entrySet.iterator();
while(it.hasNext()){
Map.Entry entry=(Map.Entry)it.next();
Object key=entry.getKey();
Object value=entry.getValue();
System.out.println(key+":"+value);
}
}
}
(2)通过Map里面的forEach(BiConsumer action)方法进行遍历
public class MapDemo02 {
public static void main(String[] args) {
Map map=new HashMap();
map.put("1","Jack");
map.put("2","Rose");
map.put("3","Lucy");
System.out.println(map);
map.forEach((key,value)-> System.out.println(key+":"+value));
}
}
(3)直接使用Map提供的values()方法直接获取值对象的Collection。剩下的遍历方式与单列集合一样。
6.3 LinkedHashMap 集合
我们使用HashMap时不能保证集合中元素存入和取出的顺序,而使用LinkedHashMap类可以保证,他是HashMap的子类,它使用双向链表来维护内部关系。因此当我们需要存入的和取出的顺序相同我们就可以用LinkedHashMap类。
6.4 TreeMap 集合
同TreeSet一样,他底层也是用二叉树来实现的,用二叉树的方式来确保键的唯一。使用如TreeSet类似。如果要存入自定义的键类型,那么就需要自定义类型去实现Comparable并重写compareTo()方法或自定义进行排序,在构造的时候传入自定义类。
6.5 Properties 集合
他是HashTable的子类。和HashMap十分相似,不同的是Hashtable是线程安全的。但是Hashtable效率要比Hashtable高。所以基本被HashMap取代,它有一个子类Properties,主要用来存放字符串类型的键值。实际开发中经常使用Properties集合类来存取应用的配置项。
使用方法如下:
public class MapDemo04 {
public static void main(String[] args) throws IOException {
//1.通过Properties进行属性文件读取操作
Properties pps=new Properties();
//加载要读取的文件
pps.load(new FileInputStream("test.properties"));
//遍历
pps.forEach((key,value)-> System.out.println(key+":"+value));
//通过Properties进行属性文件的写入
FileOutputStream out=new FileOutputStream("test.properties");
pps.setProperty("charset","UTF-8");
pps.store(out,"新增charset编码");
}
}
结果如下:
7. 泛型
用来解决集合中元素存取安全的,我们都知道我们可以任意的向集合中去存取任意类型的元素,但是当我们去取出时候,我们可能就不确定我们取出来的是什么类型的,这样当我们进行强制转换的时候可能就会出现错误。
具体使用格式如下:
ArrayList<参数化类型> list=new ArrayList<参数化类型>();
用这种方式来规定我们存入的必须是某种参数类型,这样就保证了在取出时候的类型。如果我们存入的类型不是参数化类型,在进行编译的时候就会报错。一定程度上保证了程序的健壮性和安全性。
注意:集合中如果我们没有规定参数化类型,默认我们存入的都是Object类型的。
8. 常用工具类
8.1 Collections 工具类
(1)对于List集合的常用添加和排序方法
方法声明 | 功能描述 |
static <T> boolean addAll(Collection <? super T> c,T …elements) | 将所有元素添加到集合c中 |
static void reverse(List list) | 反转指定List集合中的元素顺序 |
static void shuffle(List list) | 对List集合中的元素进行随机排序 |
statci void sort(List list) | 根据元素的自然顺序对集合List集合中的元素进行排序 |
static void swap(List list,int i,int j) | 将指定List集合中的角标i处元素和j处元素进行交换 |
(2)查找和替换操作
方法声明 | 功能描述 |
static int binarySearch(List list Object key) | 使用二分搜索法来找指定集合中的指定元素的索引,List集合中元素必须有序 |
static Object max(Collection col) | 找到集合中最大元素并返回 |
static Object min(Collection col | 找到集合中最小的元素并返回 |
static boolean replaceAll(List list,Object oldVal,Object newVal) | 用一个新值替换集合中所有旧值oldVal |
8.2 Arrays 工具类
这个类主要针对数组进行操作。
(1)静态方法sort()用来对数组进行排序
(2)静态方法binarySearch(Object[ ] a,Object key)查找元素索引,使用这个方法前提要先对数组进行排序。
(3)静态方法copyOfRange(int[ ] original,int from ,int to)拷贝元素
这个方法可以在不破坏原数组的情况下拷贝部分元素到新数组中。from表示拷贝开始的索引,to表示拷贝结束的索引(不包括本身)
(4)静态方法fill(Object[ ] a, Object val)将数组中所有元素替换为一个元素。
9. 聚合操作
主要目的简化代码量,提高执行效率。
JDK 8增加了一个Stream接口,通过它将集合和数组转换为Stream流形式,并结合Lambda表达式的优势进一步简化集合、数组中元素查找、过滤、转换等操作。
聚合操作的使用步骤:
(1)将原始集合或数组转换为Stream流
(2)对Stream流对象中的元素进行一系列的过滤、查找等中间操作,仍返回一个Stream流对象
(3)对Stream流进行遍历
统计、收集等终结操作。
使用方式如下:
public class Juhecaozuo {
public static void main(String[] args) {
//创建List对象
List<String> list=new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("张小明");
list.add("张阳");
//第一步:转换为Stream流
Stream<String> stream=list.stream();
//第二步:进行操作
Stream<String> stream1=stream.filter(i->i.startsWith("张"));
//第三步:终结操作
stream1.forEach(j-> System.out.println(j));
//通过链式一步到位
System.out.println("============");
list.stream().filter(i->i.startsWith("张")).forEach(j-> System.out.println(j));
}
}
注意:我们在进行流操作的时候不会改变源数组或集合中的数据,我们只是改变了流对象中的数据。
9.1 创建Stream流对象的几种方式
(1)所有的Colections集合都可以使用stream()静态方法获取Stream流
(2)Stream接口的of()静态方法可以获取基本类型包装类数组、引用类型数组和单个元素的Stream流对象
(3)Arrays数组工具类的stream()静态方法获取。
如下:
public class StreamDemo {
public static void main(String[] args) {
//创建一个数组
Integer[] array={9,8,3,5,2};
//将数组转换为List集合
List<Integer> list= Arrays.asList(array);
//使用集合的stream()静态方法获取Stream流
Stream<Integer> stream=list.stream();
stream.forEach(i-> System.out.print(i+" "));
System.out.println();
//2.使用Stream接口的静态方法of()获取Stream流
Stream<Integer> stream1=Stream.of(array);
stream1.forEach(i-> System.out.print(i+" "));
System.out.println();
//使用Arrays工具类的stream()静态方法获取Stream流
Stream<Integer> stream2=Arrays.stream(array);
stream2.forEach(i-> System.out.print(i+" "));
}
}
对于Map我们需要先将其变成单列集合在用单列集合的stream()方法来获取Stream流
9.2 Stream流常用方法
方法声明 | 功能描述 |
Stream<T> filter(Predicate<?super T> predicate) | 将指定流对象的元素进行过滤并返回一个流对象 |
Stream<R>map(Function<?super T, ?extends R> mapper) | 将流中元素按照一定规则映射到另一个流中 |
Stream<T> distinct() | 删除流中重复元素 |
Stream<T> sorted() | 将流中对象按自然顺序排序 |
Stream<T> limit(long maxSize) | 截取流中元素的长度 |
Stream<T> skip(long n) | 丢弃流中前n个元素 |
static<T> Stream <T> concat(Stream<?extendsT>a,Stream<?extends T> b) | 将两个流合并为一个流 |
long count() | 统计流中的元素个数 |
R collect(Collector<?super T,A,R> collector) | 将流中元素收集到一个容器中(如集合) |
Object[ ] toArray() | 将流中的元素收集到一个数组中 |
void forEach() | 对流中元素进行遍历 |
例如映射的使用:
public class MapMethDemo {
public static void main(String[] args) {
Stream<String> stream=Stream.of("a1","a2","b1","c2","c1");
stream.filter(s->s.startsWith("c"))
.map(String::toUpperCase)
.sorted().forEach(System.out::println);
}
}
收集的使用:
public class CollectDemo {
public static void main(String[] args) {
//创建一个Stream流
Stream<String> stream=Stream.of("张三","李四","张小明","张阳");
//通过filter()方法筛选以张字开头的怨怒是,通过collect进行收集到集合中
List<String> list=stream.filter(i->i.startsWith("张")).collect(Collectors.toList());
System.out.println(list);
//筛选后收集到字符串中
Stream<String> stream1=Stream.of("张三","李四","张小明","张阳");
String str=stream1.filter(i->i.startsWith("张")).collect(Collectors.joining("-"));
System.out.println(str);
}
}
注意:流一旦执行完终结操作,那么这个流就不复存在了。
9.3 Parallel Stream(并行流)
将源数据分为多个子流对象进行多线程操作(也就是多个管道流),然后将处理结果再汇总为一个流对象。这样效率会提升,但是同时带来安全性问题。
创建并行流的两种方法:
(1)通过Collection接口的parallelStream()方法变成并行流
(2)通过BaseStream接口的parallel()方法将串行流转换为并行流。
注意:不管是并行流还是串行流都拥有相同的方法。
创建方法如下:
public class ParallelStremDemo {
public static void main(String[] args) {
List<String> list= Arrays.asList("张三","李四","张小明","张阳");
//直接用Collection接口中的parallelStream()方法
Stream<String> parallelStreamstream=list.parallelStream();
System.out.println(parallelStreamstream.isParallel());
//使用BaseStream里面的parallel()方法
Stream<String> stream=Stream.of("张三","李四","张小明","张阳");
Stream<String> parallelStream2=stream.parallel();
System.out.println(parallelStream2.isParallel());
}
}