2.3java中级-集合框架

1. ArrayList

1.1 与数组的区别

1.1.1 使用数组的局限性
如果要存放多个对象,可以使用数组,但是数组有局限性
比如 声明长度是10的数组
不用的数组就浪费了
超过10的个数,又放不下

1.1.2 ArrayList存放对象
为了解决数组的局限性,引入容器类的概念。 最常见的容器类就是
ArrayList
容器的容量"capacity"会随着对象的增加,自动增长
只需要不断往容器里增加英雄即可,不用担心会出现数组的边界问题。

package collection;

import java.util.ArrayList;
import charactor.Hero;

public class TestCollection1to1 {
	
	public static void main(String[] args) {
		//容器类ArrayList,用于存放对象
		ArrayList heros=new ArrayList();
		heros.add(new Hero("盖伦"));
		System.out.println(heros.size());
		//容器的容量capacity会随着对象的增加自动增长
		//只需不断忘容器里添加英雄即可,不用担心会出现数组越界的问题
		heros.add(new Hero("提莫"));
		System.out.println(heros.size());
	}

}

1.2 常用方法

1.2.1 add添加

add 有两种用法
第一种是直接add对象,把对象加在最后面

heros.add(new Hero("hero " + i));

第二种是在指定位置加对象

heros.add(3, specialHero);


package charactor;
 
public class Hero {
    public String name;
    public float hp;
 
    public int damage;
 
    public Hero() {
 
    }
 
    // 增加一个初始化name的构造方法
    public Hero(String name) {
 
        this.name = name;
    }
 
    // 重写toString方法
    public String toString() {
        return name;
    }
 
}

package collection;

import java.util.ArrayList;
import charactor.Hero;

public class TestCollection1to2to1 {
    public static void main(String[] args) {
		ArrayList heros=new ArrayList();
		//把5个对象加入到ArrayList中
		for(int i=0;i<5;i++){
			heros.add(new Hero("hero "+i));
		}
		//在指定位置添加对象
		Hero specialHero=new Hero("special hero");
		heros.add(3,specialHero);
		System.out.println(heros.toString());
	}
}

在这里插入图片描述

1.2.2 判断是否存在

通过方法contains 判断一个对象是否在容器中
判断标准: 是否是同一个对象,而不是name是否相同

package collection;

import java.util.ArrayList;
import charactor.Hero;

public class TestCollection1to2to2 {
    public static void main(String[] args) {
		ArrayList heros=new ArrayList();
		for(int i=0;i<5;i++){
			heros.add(new Hero("hero"+i));
		}
		Hero specialHero=new Hero("specialhero");
		heros.add(3,specialHero);
		System.out.println(heros);
		//判断一个对象是否在一个容器中
		//判断标准:是否是同一个对象,而不是name是否相同
		System.out.println("虽然一个新的对象名字是hero1,但是contains的返回是:"+heros.contains(new Hero("hero1")));
		System.out.println("而对specialHero的判断,contains的返回是:"+heros.contains(specialHero));
	}
}

在这里插入图片描述

1.2.3 获取指定位置的对象

通过get获取指定位置的对象,如果输入的下标越界,一样会报错

package collection;

import java.util.ArrayList;
import charactor.Hero;

public class TestCollection1to2to3 {
    public static void main(String[] args) {
		ArrayList heros=new ArrayList();
		//把5个对象加入到ArrayList中
		for(int i=0;i<5;i++){
			heros.add(new Hero("hero"+i));
		}
		//在指定位置添加对象
		Hero specialHero=new Hero("special hero");
		heros.add(3,specialHero);
		System.out.println(heros.toString());
		
		System.out.println(heros.get(5));
		System.out.println(heros.get(6));
	}
}

在这里插入图片描述

1.2.4 获取对象所处的位置

indexOf用于判断一个对象在ArrayList中所处的位置
与contains一样,判断标准是对象是否相同,而非对象的name值是否相等

package collection;

import java.util.ArrayList;
import charactor.Hero;

public class TestCollection1to2to4 {
    public static void main(String[] args) {
		ArrayList heros=new ArrayList();
		//把5个对象加入到ArrayList中
		for(int i=0;i<5;i++){
			heros.add(new Hero("hero"+i));
		}
		//在指定位置添加对象
		Hero specialHero=new Hero("special hero");
		heros.add(3,specialHero);
		System.out.println(heros.toString());
		//获取specialHero所处的位置
		System.out.println("specialHero所处的位置"+heros.indexOf(specialHero));
		System.out.println("新的英雄但是名字是hero1,所处的位置"+heros.indexOf(new Hero("hero1")));
	}
}

在这里插入图片描述

1.2.5 删除

remove用于把对象从ArrayList中删除
remove可以根据下标删除ArrayList的元素

heros.remove(2);

也可以根据对象删除

heros.remove(specialHero);

package collection;

import java.util.ArrayList;
import charactor.Hero;

public class TestCollection1to2to5 {
    public static void main(String[] args) {
		ArrayList heros=new ArrayList();
		//把5个对象加入到ArrayList中
		for(int i=0;i<5;i++){
			heros.add(new Hero("hero "+i));
		}
		//在指定位置添加对象
		Hero specialHero=new Hero("special hero");
		heros.add(3,specialHero);
		System.out.println(heros.toString());
		heros.remove(2);
		System.out.println("删除下标为2的元素:"+heros.toString());
		heros.remove(specialHero);
		System.out.println("删除specialHero对象:"+heros.toString());
		
	}
}

在这里插入图片描述

1.2.6 替换

set用于替换指定位置的元素

package collection;

import java.util.ArrayList;
import charactor.Hero;

public class TestCollection1to2to6 {
    public static void main(String[] args) {
		ArrayList heros=new ArrayList();
		//把5个对象加入到ArrayList中
		for(int i=0;i<5;i++){
			heros.add(new Hero("hero"+i));
		}
		//在指定位置添加对象
		Hero specialHero=new Hero("special hero");
		heros.add(specialHero);
		System.out.println(heros.toString());
		heros.set(5,new Hero("hero5"));
		System.out.println("把下标为5的元素替换为hero5:"+heros);
	}
}


在这里插入图片描述

1.2.7 获取大小

size 用于获取ArrayList的大小

package collection;

import java.util.ArrayList;
import charactor.Hero;

public class TestCollection1to2to7 {
    public static void main(String[] args) {
		ArrayList heros=new ArrayList();
		//把5个对象加入到ArrayList中
		for(int i=0;i<5;i++){
			heros.add(new Hero("hero"+i));
		}
		//在指定位置添加对象
		Hero specialHero=new Hero("specialhero");
		heros.add(3,specialHero);
		System.out.println(heros.toString());
		System.out.println("获取ArrayList大小:"+heros.size());
	}
}

在这里插入图片描述

1.2.8 转换为数组

toArray可以把一个ArrayList对象转换为数组。
需要注意的是,如果要转换为一个Hero数组,那么需要传递一个Hero数组类型的对象给toArray(),这样toArray方法才知道,你希望转换为哪种类型的数组,否则只能转换为Object数组

package collection;

import java.util.ArrayList;
import charactor.Hero;

public class TestCollection1to2to8 {
    public static void main(String[] args) {
		ArrayList heros=new ArrayList();
		//把5个对象加入到ArrayList中
		for(int i=0;i<5;i++){
			heros.add(new Hero("hero"+i));
		}
		//在指定位置添加对象
		Hero specialHero=new Hero("specialhero");
		heros.add(specialHero);
		System.out.println(heros);
		Hero hs[]=(Hero[])heros.toArray(new Hero[]{});
		System.out.println("数组:"+hs);
	}
}

在这里插入图片描述

1.2.9 把另 一个容器所有对象都加进来

addAll 把另一个容器所有对象都加进来

package collection;

import java.util.ArrayList;
import charactor.Hero;

public class TestCollection1to2to9 {
    public static void main(String[] args) {
		ArrayList heros=new ArrayList();
		//把5个对象加入到ArrayList中
		for(int i=0;i<5;i++){
			heros.add(new Hero("hero"+i));
		}
		Hero specialHero=new Hero("specialhero");
		heros.add(specialHero);
		System.out.println("heros:\t"+heros);
		ArrayList otherheros=new ArrayList();
		otherheros.add(new Hero("heroa"));
		otherheros.add(new Hero("herob"));
		otherheros.add(new Hero("heroc"));
		System.out.println("otherheros:\t"+otherheros);
				
		heros.addAll(otherheros);
		System.out.println("添加了otherheros之后的heros:\t"+heros);
	}
}

在这里插入图片描述

1.2.10 清空

clear 清空一个ArrayList

package collection;

import java.util.ArrayList;
import charactor.Hero;

public class TestCollection1to2to10 {
    public static void main(String[] args) {
		ArrayList heros=new ArrayList();
		//把5个对象加入到ArrayList中
		for(int i=0;i<5;i++){
			heros.add(new Hero("hero "+i));
		}
		
		Hero specialHero=new Hero("special hero");
		heros.add(3,specialHero);
		System.out.println(heros);
		heros.clear();
		System.out.println(heros.toString());
	}
}

在这里插入图片描述

1.2.11 练习-判断是否相同

如果就是要判断集合里是否存在一个 name等于 "hero1"的对象,应该怎么做?

package collection;

import java.util.ArrayList;
import charactor.Hero;

public class TestCollection1to2to11 {
   public static void main(String[] args) {
	ArrayList heros=new ArrayList();
	int f=0;
	String str="hero1";
	for(int i=0;i<5;i++)
		heros.add(new Hero("hero"+i));
	for(int i=0;i<heros.size();i++){
		String str1=heros.get(i).toString();
		if(str1.equals(str)){
			System.out.println("yes");
			f=1;
		}
	}
	if(f==0)
	 System.out.println("no");
}
}

1.3 List接口

1.3.1 ArrayList和List

ArrayList实现了接口List
常见的写法会把引用声明为接口List类型
注意:是java.util.List,而不是java.awt.List

package collection;

import java.util.ArrayList;
import java.util.List;
import charactor.Hero;

public class TestCollection1to3to1 {
	public static void main(String[] args) {
		//ArrayList实现了List接口
		//常见的方法会把引用声明为接口List类型
		//接口引用指向子类对象(多态)
		List heros=new ArrayList();
		heros.add(new Hero("盖伦"));
		System.out.println(heros.size());
	}

}

1.3.2 List接口的方法

因为ArrayList实现了List接口,所以List接口的方法ArrayList都实现了。
在ArrayList 常用方法章节有详细的讲解,在此不作赘述

1.4 泛型 Gerneric

1.4.1 泛型 Generic

不指定泛型的容器,可以存放任何类型的元素
指定了泛型的容器,只能存放指定类型的元素以及其子类

package collection;

import java.util.ArrayList;
import java.util.List;
import property.Item;
import charactor.Hero;

public class TestCollection1to3to2 {
    public static void main(String[] args) {
		//对于不使用泛型的容器,可以往里边放英雄,也可以放物品
    	List heros=new ArrayList();
    	heros.add(new Hero("盖伦"));
    	//本来用来放英雄的容器,现在也可以放物品
    	heros.add(new Item("冰杖"));
    	//对象转型会出现问题
    	Hero h1=(Hero)heros.get(0);
    	//尤其是在容器里放很多对象的时候,就记不清哪个位置放的是哪种类型的对象了
    	//Hero h2=(Hero)heros.get(1);
    	//引入泛型Generic
    	//声明容器的时候,就指定了这种容器,只能放Hero及其子类,放其他的会报错
    	List<Hero> genericheros=new ArrayList<Hero>();
    	genericheros.add(new Hero("盖伦"));
    	//如果不是Hero类型,根本就放不进去
    	//genericheros.add(new Item("冰杖"));
    	//放Hero子类的时候,取数据的时候不需要再转型,因为里边肯定放的是Hero或其子类
	}
}

1.4.2 泛型的简写

为了不使编译器出现警告,需要前后都使用泛型,像这样:

List genericheros = new ArrayList();

不过JDK7提供了一个可以略微减少代码量的泛型简写方式

List genericheros2 = new ArrayList<>();

后面的泛型可以用<>来代替,聊胜于无吧

1.4.3 练习-支持泛型的ArrayList

借助泛型和前面学习的面向对象的知识,设计一个ArrayList,使得这个ArrayList里,又可以放Hero,又可以放Item,但是除了这两种对象,其他的对象都不能放

我把Item继承了Hero的类,这样不就只有两个对象了

package collection;

import java.util.ArrayList;
import charactor.Hero;
import property.Item;


public class TestColection1to3to3 {
	public static void main(String[] args) {
		ArrayList<Hero> heros=new ArrayList<>();
		heros.add(new Hero("盖伦"));
		heros.add(new Item("冰杖"));
		Hero h1=heros.get(0);
		Item i1=(Item)heros.get(1);
		System.out.println(h1.name+"    "+i1.name);
	}

}

1.5 泛型遍历

1.5.1 用for循环遍历

通过前面的学习,知道了可以用size()和get()分别得到大小,和获取指定位置的元素,结合for循环就可以遍历出ArrayList的内容

package collection;

import java.util.List;
import java.util.ArrayList;
import charactor.Hero;

public class TestCollection1to5to1 {
    public static void main(String[] args) {
		List<Hero> heros=new ArrayList<>();
		for(int i=0;i<5;i++)
			 heros.add(new Hero("Hero"+i));
		System.out.println("---------for循环---------");
		for(int i=0;i<heros.size();i++){
			Hero h=heros.get(i);
			System.out.println(h);
		}
	}
}

在这里插入图片描述

1.5.2 迭代器遍历

使用迭代器Iterator遍历集合中的元素
在这里插入图片描述

package collection;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import charactor.Hero;

public class TestCollection1to5to2 {
	public static void main(String[] args) {
		List<Hero> heros=new ArrayList<>();
		for(int i=0;i<5;i++)
			 heros.add(new Hero("hero"+i));
		//使用迭代器
		System.out.println("------------使用while的iterator-----------");
		Iterator<Hero> it=heros.iterator();
		//从最开始的位置就判断“下一个”是否有数据
		//如果有就通过next取出来,并且把指针向下移动
		//直到“下一个”位置没有数据
		while(it.hasNext()){
			Hero h=it.next();
			System.out.println(h);
		}
		System.out.println("----------使用for的iterator");
		for(Iterator<Hero> iterator=heros.iterator();iterator.hasNext();){
			Hero h=iterator.next();
			System.out.println(h);
		}
	}

}

在这里插入图片描述

1.5.3 用增强型for循环

使用增强型for循环可以非常方便的遍历ArrayList中的元素,这是很多开发人员的首选。

不过增强型for循环也有不足:
无法用来进行ArrayList的初始化
无法得知当前是第几个元素了,当需要只打印单数元素的时候,就做不到了。 必须再自定下标变量。

package collection;

import java.util.ArrayList;
import java.util.List;

import charactor.Hero;

public class TestCollection1to5to3 {
   public static void main(String[] args) {
	List<Hero> heros=new ArrayList<>();
	for(int i=0;i<5;i++)
		heros.add(new Hero("hero"+i));
	for(Hero h:heros){
		System.out.println(h);
	}
}
}

1.5.4 练习-删除ArrayList中的数据

首先初始化一个Hero集合,里面放100个Hero对象,名称分别是从
hero 0
hero 1
hero 2

hero 99.

通过遍历的手段,删除掉名字编号是8的倍数的对象

package collection;

import java.util.List;
import java.util.ArrayList;

import charactor.Hero;

public class TestCollection1to5to4 {
   public static void main(String[] args) {
	List<Hero> heros=new ArrayList<>();
	for(int i=0;i<100;i++)
		heros.add(new Hero("hero"+i));
	int sentinel=0;
	//remove后,List的各个元素index会改变,也就是List会缩小
	//所以来一个sentinel记录缩小
	for(int i=0;i<heros.size();i+=8){
		heros.remove(i-sentinel);
		sentinel+=1;
	}
	System.out.println(heros);	
}
}

2. 其他集合

2.1 LinkedList

序列分先进先出FIFO,先进后出FILO
FIFO在Java中又叫Queue 队列
FILO在Java中又叫Stack 栈

2.1.1 LinkedList 与 List接口

与ArrayList一样,LinkedList也实现了List接口,诸如add,remove,contains等等方法。 详细使用,请参考 ArrayList 常用方法,在此不作赘述。

接下来要讲的是LinkedList的一些特别的地方

2.1.2 双向链表 - Deque

除了实现了List接口外,LinkedList还实现了双向链表结构Deque,可以很方便的在头尾插入删除数据

什么是链表结构: 与数组结构相比较,数组结构,就好像是电影院,每个位置都有标示,每个位置之间的间隔都是一样的。 而链表就相当于佛珠,每个珠子,只连接前一个和后一个,不用关心除此之外的其他佛珠在哪里。

package collection;

import java.util.LinkedList;

import charactor.Hero;

public class TestCollection2to1to2 {
	public static void main(String[] args) {
		//LinekedList是一个双向链表结构的List
		LinkedList<Hero> ll=new LinkedList<>();
		//所以可以很方便的在头部和尾部插入元素
		//在最后插入新的元素
		ll.addLast(new Hero("hero"+1));ll.addLast(new Hero("hero"+2));
		System.out.println(ll);
		//在最前面插入元素
		ll.addFirst(new Hero("heroa"));ll.addFirst(new Hero("herob"));
		System.out.println("ll:"+ll);
		//查看最前面的元素
		System.out.println("最前边的元素"+ll.getFirst());
		//查看最后边的元素
		System.out.println("最后边的元素"+ll.getLast());
		//取出最前边的元素
		System.out.println(ll.removeFirst());
		//取出最后边的元素
		System.out.println(ll.removeLast());
		System.out.println(ll);
	}

}

在这里插入图片描述

2.1.3 队列 - Queue

LinkedList 除了实现了List和Deque外,还实现了Queue接口(队列)。
Queue是先进先出队列 FIFO,常用方法:
offer 在最后添加元素
poll 取出第一个元素
peek 查看第一个元素

package collection;

import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import charactor.Hero;

public class TestCollection2to1to3 {
	public static void main(String[] args) {
		//和ArrayList一样,LinkedList也实现了List接口
		List ll=new LinkedList<Hero>();
		//所不同的是LinkedList还实现了Deque,进而又实现了Queue这个接口
		//Queue代表FIFO先进先出的队列
		Queue<Hero> q=new LinkedList<Hero>();
		//加在队列的最后面
		q.offer(new Hero("hero1"));q.offer(new Hero("hero2"));
		q.offer(new Hero("hero3"));q.offer(new Hero("hero4"));
		System.out.println("初始化队列:\t"+q);
		//取出第一个Hero,FIFO先进先出
		Hero h=q.poll();
		System.out.println(h);
		System.out.println("取出第一个元素之后的队列:"+q);
		//把第一个元素拿出来看一看,但是不取出来
		h=q.peek();
		System.out.println("查看peek()第一个元素:\t"+h);
		System.out.println("查看第一个元素并不会导致第一个元素被取出来:\t"+q);
	}

}

在这里插入图片描述

2.1.4 ArrayList 与 LinkedList的区别

ArrayList 与 LinkedList的区别是面试常常会问到的考题
具体区别,详见 ArrayList 与 LinkedList的区别

package collection;

import java.util.LinkedList;

import charactor.Hero;

public class TestCollection2to1to4  {
    LinkedList<Hero> heros=new LinkedList<>();
	public static void main(String[] args) {
		TestCollection2to1to4 h=new TestCollection2to1to4();
		for(int i=0;i<5;i++) 
			h.push(new Hero("hero"+i));
		for(int i=0;i<5;i++)
			 System.out.println("依次取出对象"+h.pull());
		
	}
	//把英雄推入到最后位置
	public void push(Hero h){
		heros.addLast(h);		
	}
	//把最后一个英雄取出来
    public Hero pull(){
    	return heros.removeLast();
    }
    //查看最后一个英雄
    public Hero peek(){
    	return heros.getLast();
    }
}

在这里插入图片描述

2.2 二叉树

2.2.1 二叉树概念

二叉树由各种节点组成
二叉树特点:
每个节点都可以有左子节点,右子节点
每一个节点都有一个值

package collection;

public class Node {
	// 左子节点
	public Node leftNode;
	// 右子节点
	public Node rightNode;
	// 值
	public Object value;
}

2.2.2 二叉树排序-插入数据

假设通过二叉树对如下10个随机数进行排序
67,7,30,73,10,0,78,81,10,74
排序的第一个步骤是把数据插入到该二叉树中
插入基本逻辑是,小、相同的放左边,大的放右边

  1. 67 放在根节点
  2. 7 比 67小,放在67的左节点
  3. 30 比67 小,找到67的左节点7,30比7大,就放在7的右节点
  4. 73 比67大, 放在67的右节点
  5. 10 比 67小,找到67的左节点7,10比7大,找到7的右节点30,10比30小,放在30的左节点。

  6. 10比67小,找到67的左节点7,10比7大,找到7的右节点30,10比30小,找到30的左节点10,10和10一样大,放在左边

2.2.3 二叉树排序-遍历

通过上一个步骤的插入行为,实际上,数据就已经排好序了。 接下来要做的是看,把这些已经排好序的数据,遍历成我们常用的List或者数组的形式

二叉树的遍历分左序,中序,右序
左序即: 中间的数遍历后放在左边
中序即: 中间的数遍历后放在中间
右序即: 中间的数遍历后放在右边
如图所见,我们希望遍历后的结果是从小到大的,所以应该采用中序遍历

package collection;

import java.util.ArrayList;
import java.util.List;

public class Node1 {
	//左节点
	public Node1 leftNode;
	//右节点
	public Node1 rightNode;
	//值
	public Object value;
	public void add(Object v){
		//如果当前节点没有值,就把数据放在当前节点
		if(null==value) value=v;
		else{
			//如果当前节点有值,就进行判断,新增的值与当前值的大小关系
			if(((Integer)v)-((Integer)value)<=0){
				if(null==leftNode)
					leftNode=new Node1();
				leftNode.add(v);
			}
			else{
				if(null==rightNode)
					rightNode=new Node1();
				rightNode.add(v);
		    }
	    }
	}
	public List<Object> values(){
		List<Object> values=new ArrayList<>();
		//左结点的遍历结果
		if(null!=leftNode) values.addAll(leftNode.values());
		//当前结点
		values.add(value);
		//右结点的遍历结果
		if(null!=rightNode) values.addAll(rightNode.values());
	    return values;	
	}
	public static void main(String[] args) {
		int randoms[]=new int[]{67,7,30,73,10,0,78,81,10,74};
		Node1 roots=new Node1();
		for(int number:randoms)
			roots.add(number);
		System.out.println(roots.values());
	}
}

在这里插入图片描述

2.2.4 练习-英雄二叉树

根据上面的学习和理解,设计一个Hero二叉树,HeroNode.
可以向这个英雄二叉树插入不同的Hero对象,并且按照Hero的血量倒排序。

随机生成10个Hero对象,每个Hero对象都有不同的血量值,插入这个HeroNode后,把排序结果打印出来。

package collection;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;


public class Node2 {
	public Node2 leftNode;
	public Node2 rightNode;
	public Node3 node;
	public void add(Node3 v){
	    if(null==node) node=v;
	    else{
	    	if((Integer)node.hp-((Integer)v.hp)<=0){
	    		if(null==leftNode)
	    			leftNode=new Node2();
	    		leftNode.add(v);
	    	}
	    	else{
	    		if(null==rightNode)
	    			rightNode=new Node2();
	    		rightNode.add(v);
	    	}
	    }
	}
	public List<String> values(){
		List<String> values=new ArrayList<String>();
		if(null!=leftNode) values.addAll(leftNode.values());
		values.add("name:"+node.name+" hp:"+node.hp);
		if(null!=rightNode) values.addAll(rightNode.values());
		return values;
	}
	public static void main(String[] args) {
		 Node3[] heros=new Node3[5];
		 for(int i=0;i<5;i++)
			 heros[i]=new Node3("hero"+i,(int)(Math.random()*1000));
		Node2 roots=new Node2();
		for(Node3 hero:heros){
			roots.add(hero);
		}
		System.out.println(roots.values());
	}

}


package collection;

public class Node3 {
		public String name;
		public int hp;
		public Node3(String name,int hp){
			this.name=name;this.hp=hp;
		}
		public Node3(){
			
		}
}

2.3 HashMap

2.3.1 HashMap的键值对

HashMap储存数据的方式是—— 键值对

package collection;

import java.util.HashMap;

public class TestCollection2to3to1 {
	public static void main(String[] args) {
		HashMap<String,String> directory=new HashMap<>();
		directory.put("adc","物理英雄");
		directory.put("apc", "魔法英雄");
		directory.put("t","坦克");
		System.out.println(directory.get("t"));
	}

}

在这里插入图片描述

2.3.2 键不能重复,值可以重复

对于HashMap而言,key是唯一的,不可以重复的。
所以,以相同的key 把不同的value插入到 Map中会导致旧元素被覆盖,只留下最后插入的元素。
不过,同一个对象可以作为值插入到map中,只要对应的key不一样

package collection;

import java.util.HashMap;
import charactor.Hero;

public class TestCollection2to3to2 {
	public static void main(String[] args) {
		HashMap<String,Hero> heroMap=new HashMap<String,Hero>();
		heroMap.put("gareen", new Hero("gareen1"));
		System.out.println(heroMap);
		//key位gareen已经有value了,再以gareen作为key放入数据,会导致原英雄被覆盖
		heroMap.put("gareen",new Hero("gareen2"));
		System.out.println(heroMap);
		heroMap.clear();
		Hero gareen=new Hero("gareen");
		//同一个对象可以作为值插入到map中,只要对应的key值不一样
		heroMap.put("hero1",gareen);heroMap.put("hero2",gareen);
		System.out.println(heroMap);
	}

}

在这里插入图片描述

2.3.3 练习-查找内容性能比较

准备一个ArrayList其中存放3000000(三百万个)Hero对象,其名称是随机的,格式是hero-[4位随机数]
hero-3229
hero-6232
hero-9365

因为总数很大,所以几乎每种都有重复,把名字叫做 hero-5555的所有对象找出来
要求使用两种办法来寻找

  1. 不使用HashMap,直接使用for循环找出来,并统计花费的时间
  2. 借助HashMap,找出结果,并统计花费的时间
package collection;

import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;

import charactor.Hero;

public class TestCollection2to3to3 {
	public static void main(String[] args) {
		List<Hero> hs=new ArrayList<>();
		System.out.println("初始化开始");
		for(long i=0;i<300000;i++){
			Hero h=new Hero("hero-"+((int)Math.random()*9000+1000));
			hs.add(h);			
		}
		HashMap<String,List<Hero>> heroMap=new HashMap<>();
		for(Hero h:hs){
			List<Hero> list=heroMap.get(h.name);
			if(list==null){
				list=new ArrayList<Hero>();
				heroMap.put(h.name,list);
			}
			list.add(h);
		}
		System.out.print("初始化结束");
		System.out.print("开始查找");
		findByMap(heroMap);
		findByIterator(hs);
	}
	private static List<Hero> findByMap(HashMap<String,List<Hero>> m)
	{
		long start=System.currentTimeMillis();
		List<Hero> result=m.get("hero-1000");
		long end=System.currentTimeMillis();
		System.out.printf("通过map查找,一共找到了%d个英雄,耗时%d毫秒%n",result.size(),end-start);
		return result;		
	}
	private static List<Hero> findByIterator(List<Hero> hs)
	{
		long start=System.currentTimeMillis();
		List<Hero> result=new ArrayList<>();
		for(Hero h:hs){
			if(h.name.equals("hero-1000")){
				result.add(h);
			}
		}
		long end=System.currentTimeMillis();
		System.out.printf("通过for查找,一共找到了%d个英雄,耗时%d毫秒%n",result.size(),end-start);
		return result;
	}

}

在这里插入图片描述

2.4 HashSet

2.4.1 元素不能重复

Set中的元素,不能重复

package collection;

import java.util.HashSet;

public class TestCollection2to4to1 {
    public static void main(String[] args) {
		HashSet<String> names=new HashSet<String>();
		names.add("gareen");
		System.out.println(names);
		//第二次插入同样的数据,是插不进去的,容器中智慧保留一个
		names.add("gareen");
        System.out.println(names);
	}
}

在这里插入图片描述

2.4.2 没有顺序

Set中的元素,没有顺序。
严格的说,是没有按照元素的插入顺序排列

HashSet的具体顺序,既不是按照插入顺序,也不是按照hashcode的顺序。关于hashcode有专门的章节讲解: hashcode 原理。

以下是HashSet源代码中的部分注释
/**

  • It makes no guarantees as to the iteration order of the set;
  • in particular, it does not guarantee that the order will remain constant over time.
    */

不保证Set的迭代顺序; 确切的说,在不同条件下,元素的顺序都有可能不一样

换句话说,同样是插入0-9到HashSet中, 在JVM的不同版本中,看到的顺序都是不一样的。 所以在开发的时候,不能依赖于某种臆测的顺序,这个顺序本身是不稳定的

package collection;

import java.util.HashSet;

public class TestCollection2to4to2 {
	public static void main(String[] args) {
		HashSet<Integer> numbers=new HashSet<Integer>();
		numbers.add(9);
		numbers.add(512);
		numbers.add(1);
		//Set中的元素顺序,不是按照插入顺序
		System.out.println(numbers);
	}

}

在这里插入图片描述

2.4.3 遍历

Set不提供get()来获取指定位置的元素
所以遍历需要用到迭代器,或者增强型for循环

package collection;

import java.util.HashSet;
import java.util.Iterator;

public class TestCollection2to4to3 {
	public static void main(String[] args) {
		HashSet<Integer> numbers=new HashSet<Integer>();
		for(int i=0;i<20;i++)
			 numbers.add(i);
		//set不提供get方法来获取指定位置的元素
		
		//遍历set可以采用迭代器Iterator
		for(Iterator<Integer> iterator=numbers.iterator();iterator.hasNext();){
			Integer i=(Integer)iterator.next();
			System.out.print(i+" ");
		}
		System.out.println();
		//或者采用增强型for循环
		for(Integer i:numbers){
			System.out.print(i+" ");
		}
	}

}

在这里插入图片描述

2.4.4 HashSet和HashMap的关系

通过观察HashSet的源代码(如何查看源代码)
可以发现HashSet自身并没有独立的实现,而是在里面封装了一个Map.
HashSet是作为Map的key而存在的
而value是一个命名为PRESENT的static的Object对象,因为是一个类属性,所以只会有一个。

private static final Object PRESENT = new Object();

2.4.5 练习-HashSet

在比较字符串章节,有一个同样的练习
创建一个长度是100的字符串数组
使用长度是2的随机字符填充该字符串数组
统计这个字符串数组里重复的字符串有多少种
使用HashSet来解决这个问题

package collection;

import java.util.HashSet;

public class TestCollection2to4to4 {
   public static void main(String[] args) {
	String[] str=new String[100];
	for(int i=0;i<100;i++){
		char[] ch=new char[2];
		for(int j=0;j<2;){
			char a=(char)(Math.random()*(122-65)+65);
			if(Character.isLetter(a)){
				ch[j]=a;j++;
			}
		}
		str[i]=new String(ch);
	}
	System.out.println("str的内容为");
	for(String a:str){
		System.out.println(a);
	}
	System.out.println("-----------------");
	HashSet<String> content =new HashSet<>();
	HashSet<String> plus=new HashSet<>();
	for(int i=0;i<str.length;i++){
		if(content.contains(str[i])){
			plus.add(str[i]);
		}
		else
			content.add(str[i]);
	}
	System.out.printf("总共有%d种相同的字符串,分别为:\n",plus.size());
	for(String b:plus)
		System.out.println(b);
}
}

2.5 Collection

Collection是一个接口
Collection是 Set List Queue和 Deque的接口
Queue: 先进先出队列
Deque: 双向链表

注:Collection和Map之间没有关系,Collection是放一个一个对象的,Map 是放键值对的
注:Deque 继承 Queue,间接的继承了 Collection
在这里插入图片描述

2.6 Collections 是一个类,容器的工具类,就如同Arrays是数组的工具类

2.6.1 反转

reverse 使List中的数据发生翻转

package collection;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class TestCollection2to6to1 {
   public static void main(String[] args) {
	   //初始化numbers
	List<Integer> numbers=new ArrayList<>();
	
	for(int i=0;i<10;i++){
		numbers.add(i);
	}
	System.out.println("集合中的数据");
	System.out.println(numbers);
	Collections.reverse(numbers);
	System.out.println("翻转后的集合中的数据:");
	System.out.println(numbers);
}
}

在这里插入图片描述

2.6.2 混淆

shuffle 混淆List中数据的顺序

package collection;

import java.util.ArrayList;
import java.util.List;
import java.util.Collections;

public class TestCollection2to6to2 {
	public static void main(String[] args) {
		List<Integer> numbers=new ArrayList<>();
		for(int i=0;i<10;i++) numbers.add(i);
		System.out.println("集合中的数据:");
		System.out.println(numbers);
		Collections.shuffle(numbers);
		System.out.println("混淆后的数据:");
		System.out.println(numbers);
	}

}

在这里插入图片描述

2.6.3 排序

sort 对List中的数据进行排序

package collection;

import java.util.ArrayList;
import java.util.List;
import java.util.Collections;

public class TestCollection2to6to2 {
	public static void main(String[] args) {
		List<Integer> numbers=new ArrayList<>();
		for(int i=0;i<10;i++) numbers.add(i);
		System.out.println("集合中的数据:");
		System.out.println(numbers);
		Collections.shuffle(numbers);
		System.out.println("混淆后的数据:");
		System.out.println(numbers);
		Collections.sort(numbers);
		System.out.println("排序之后的数据:");
		System.out.println(numbers);
	}

}

在这里插入图片描述

2.6.4 交换

swap 交换两个数据的位置

package collection;

import java.util.ArrayList;
import java.util.List;
import java.util.Collections;

public class TestCollection2to6to4 {
	public static void main(String[] args) {
		List<Integer> numbers=new ArrayList<>();
		for(int i=0;i<10;i++) numbers.add(i);
		System.out.println("集合中的数据:");
		System.out.println(numbers);
		Collections.swap(numbers, 0, 5);
		System.out.println("交换位置0和位置5的数据:");
		System.out.println(numbers);
	}

}

在这里插入图片描述

2.6.5 滚动

rotate 把List中的数据,向右滚动指定单位的长度

package collection;

import java.util.ArrayList;
import java.util.List;
import java.util.Collections;

public class TestCollection2to6to5 {
	public static void main(String[] args) {
		List<Integer> numbers=new ArrayList<>();
		for(int i=0;i<10;i++) numbers.add(i);
		System.out.println("集合中的数据:");
		System.out.println(numbers);
		Collections.rotate(numbers,2);
		System.out.println("把集合向右滚动2个单位后:");
		System.out.println(numbers);
	}

}

在这里插入图片描述

2.6.6 线程安全化

synchronizedList 把非线程安全的List转换为线程安全的List。 因为截至目前为止,还没有学习线程安全的内容,暂时不展开。 线程安全的内容将在多线程章节展开。

package collection;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class TestCollection {
	public static void main(String[] args) {
		List<Integer> numbers = new ArrayList<>();

		System.out.println("把非线程安全的List转换为线程安全的List");
        List<Integer> synchronizedNumbers = (List<Integer>) Collections.synchronizedList(numbers);

	}
}

2.6.7 练习-统计概率

package collection;

import java.util.ArrayList;
import java.util.List;
import java.util.Collections;

public class TestCollection2to6to7 {
	public static void main(String[] args) {
		List<Integer> numbers=new ArrayList<>();
		int t=0;
		for(int i=0;i<9;i++) numbers.add(i);
		for(int i=0;i<1000000;i++){
			Collections.shuffle(numbers);
			if(numbers.get(0)==3&&numbers.get(1)==1&&numbers.get(2)==4)
				t++;
		}
		System.out.println("shuffle 1000,000 次,统计3 1 4出现的概率:");
		System.out.println((double)t*100.0/1000000+"%");
	}
 }

在这里插入图片描述

3 ArrayList vs HashSet

3.1 ArrayList vs LinkedList

3.1.1 是否有顺序

ArrayList: 有顺序
HashSet: 无顺序

HashSet的具体顺序,既不是按照插入顺序,也不是按照hashcode的顺序。关于hashcode有专门的章节讲解: hashcode 原理。

以下是HasetSet源代码中的部分注释
不保证Set的迭代顺序; 确切的说,在不同条件下,元素的顺序都有可能不一样
换句话说,同样是插入0-9到HashSet中, 在JVM的不同版本中,看到的顺序都是不一样的。 所以在开发的时候,不能依赖于某种臆测的顺序,这个顺序本身是不稳定的

3.1.2 能否重复

List中的数据可以重复
Set中的数据不能够重复
重复判断标准是:
首先看hashcode是否相同
如果hashcode不同,则认为是不同数据
如果hashcode相同,再比较equals,如果equals相同,则是相同数据,否则是不同数据
更多关系hashcode,请参考hashcode原理

3.1.3 练习-不重复的随机数

package collection;

import java.util.HashSet;
import java.util.Set;

public class TestCollection3to1to2 {
    public static void main(String[] args) {
		Set<Integer> numbers=new HashSet<>();
		while(numbers.size()<50){
			int i=(int)(Math.random()*10000);
			numbers.add(i);
		}
		System.out.println("得到50个不重复的随机数:");
		System.out.println(numbers);
	}
    
}

3.2 ArrayList vs LinkedList

3.2.1 ArrayList和LinkedList的区别

ArrayList 插入,删除数据慢
LinkedList, 插入,删除数据快
ArrayList是顺序结构,所以定位很快,指哪找哪。 就像电影院位置一样,有了电影票,一下就找到位置了。
LinkedList 是链表结构,就像手里的一串佛珠,要找出第99个佛珠,必须得一个一个的数过去,所以定位慢

3.3 HashMap和Hashtable的区别

3.3.1

HashMap和Hashtable都实现了Map接口,都是键值对保存数据的方式
区别1:
HashMap可以存放 null
Hashtable不能存放null
区别2:
HashMap不是线程安全的类
Hashtable是线程安全的类

鉴于目前学习的进度,不对线程安全做展开,在线程章节会详细讲解

package collection;

import java.util.HashMap;
import java.util.Hashtable;

public class TestCollection {
	public static void main(String[] args) {
		
		//HashMap和Hashtable都实现了Map接口,都是键值对保存数据的方式
		
		HashMap<String,String> hashMap = new HashMap<String,String>();
		
		//HashMap可以用null作key,作value
		hashMap.put(null, "123");
		hashMap.put("123", null);
		
		Hashtable<String,String> hashtable = new Hashtable<String,String>();
		//Hashtable不能用null作key,不能用null作value
		hashtable.put(null, "123");
		hashtable.put("123", null);

	}
}

3.3.2 练习-反转key和value

使用如下键值对,初始化一个HashMap:
adc - 物理英雄
apc - 魔法英雄
t - 坦克

对这个HashMap进行反转,key变成value,value变成key
提示: keySet()可以获取所有的key, values()可以获取所有的value

package collection;

import java.util.HashMap;
import java.util.Set;

public class TestCollection3to3to2 {
	public static void main(String[] args) {
		HashMap<String,String> heros=new HashMap<>(),heross=new HashMap<>();
		heros.put("adc","物理英雄");
		heros.put("apc","魔法英雄");
		heros.put("t","坦克");
		System.out.println(heros);
		Set<String> keys=heros.keySet();
		for(String str:keys){
			heross.put(heros.get(str), str);
		}
		System.out.println(heross);
		
	}

}

在这里插入图片描述

3.4 几种set

3.4.1 HashSet | LinkedHashSet | TreeSet

HashSet: 无序
LinkedHashSet: 按照插入顺序
TreeSet: 从小到大排序

package collection;
 
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.TreeSet;
 
public class TestCollection {
    public static void main(String[] args) {
        HashSet<Integer> numberSet1 =new HashSet<Integer>();
        //HashSet中的数据不是按照插入顺序存放
        numberSet1.add(88);
        numberSet1.add(8);
        numberSet1.add(888);
         
        System.out.println(numberSet1);
         
        LinkedHashSet<Integer> numberSet2 =new LinkedHashSet<Integer>();
        //LinkedHashSet中的数据是按照插入顺序存放
        numberSet2.add(88);
        numberSet2.add(8);
        numberSet2.add(888);
         
        System.out.println(numberSet2);
        TreeSet<Integer> numberSet3 =new TreeSet<Integer>();
        //TreeSet 中的数据是进行了排序的
        numberSet3.add(88);
        numberSet3.add(8);
        numberSet3.add(888);
         
        System.out.println(numberSet3);
         
    }
}

3.4.2 练习-既不重复,又有顺序

利用LinkedHashSet的既不重复,又有顺序的特性,把Math.PI中的数字,按照出现顺序打印出来,相同数字,只出现一次

package Collection;
import java.util.LinkedHashSet;
public class Test7 {
    public static void main(String[] args) {
        LinkedHashSet<Integer> set = new LinkedHashSet<>();
        double pi = Math.PI;
        while(set.size()<10) {
            set.add((Integer)(int)(pi%10));
            pi*=10;
        }
        System.out.println(set);
    }
}

4 其他

4.1 hashcode原理

4.1.1 List查找的低效率

假设在List中存放着无重复名称,没有顺序的2000000个Hero
要把名字叫做“hero 1000000”的对象找出来
List的做法是对每一个进行挨个遍历,直到找到名字叫做“hero 1000000”的英雄。
最差的情况下,需要遍历和比较2000000次,才能找到对应的英雄。
测试逻辑:

  1. 初始化2000000个对象到ArrayList中
  2. 打乱容器中的数据顺序
  3. 进行10次查询,统计每一次消耗的时间
    不同计算机的配置情况下,所花的时间是有区别的。 在本机上,花掉的时间大概是600毫秒左右

4.1.2 HashMap的性能表现

使用HashMap 做同样的查找

  1. 初始化2000000个对象到HashMap中。
  2. 进行10次查询
  3. 统计每一次的查询消耗的时间
    可以观察到,几乎不花时间,花费的时间在1毫秒以内

4.1.3 HashMap原理与字典

在展开HashMap原理的讲解之前,首先回忆一下大家初中和高中使用的汉英字典。

比如要找一个单词对应的中文意思,假设单词是Lengendary,首先在目录找到Lengendary在第 555页。

然后,翻到第555页,这页不只一个单词,但是量已经很少了,逐一比较,很快就定位目标单词Lengendary。

555相当于就是Lengendary对应的hashcode

4.1.4 分析HashMap性能卓越的原因

-----hashcode概念-----
所有的对象,都有一个对应的hashcode(散列值)
比如字符串“gareen”对应的是1001 (实际上不是,这里是方便理解,假设的值)
比如字符串“temoo”对应的是1004
比如字符串“db”对应的是1008
比如字符串“annie”对应的也是1008

-----保存数据-----
准备一个数组,其长度是2000,并且设定特殊的hashcode算法,使得所有字符串对应的hashcode,都会落在0-1999之间
要存放名字是"gareen"的英雄,就把该英雄和名称组成一个键值对,存放在数组的1001这个位置上
要存放名字是"temoo"的英雄,就把该英雄存放在数组的1004这个位置上
要存放名字是"db"的英雄,就把该英雄存放在数组的1008这个位置上
要存放名字是"annie"的英雄,然而 "annie"的hashcode 1008对应的位置已经有db英雄了,那么就在这里创建一个链表,接在db英雄后面存放annie

-----查找数据-----
比如要查找gareen,首先计算"gareen"的hashcode是1001,根据1001这个下标,到数组中进行定位,(根据数组下标进行定位,是非常快速的) 发现1001这个位置就只有一个英雄,那么该英雄就是gareen.
比如要查找annie,首先计算"annie"的hashcode是1008,根据1008这个下标,到数组中进行定位,发现1008这个位置有两个英雄,那么就对两个英雄的名字进行逐一比较(equals),因为此时需要比较的量就已经少很多了,很快也就可以找出目标英雄
这就是使用hashmap进行查询,非常快原理。

这是一种用空间换时间的思维方式

4.1.5 HashSet判断是否重复

HashSet的数据是不能重复的,相同数据不能保存在一起,到底如何判断是否是重复的呢?
根据HashSet和HashMap的关系,我们了解到因为HashSet没有自身的实现,而是里面封装了一个HashMap,所以本质上就是判断HashMap的key是否重复。

再通过上一步的学习,key是否重复,是由两个步骤判断的:
hashcode是否一样
如果hashcode不一样,就是在不同的坑里,一定是不重复的
如果hashcode一样,就是在同一个坑里,还需要进行equals比较
如果equals一样,则是重复数据
如果equals不一样,则是不同数据。

4.2 比较器

4.2.1 Comparator

假设Hero有三个属性 name,hp,damage
一个集合中放存放10个Hero,通过Collections.sort对这10个进行排序
那么到底是hp小的放前面?还是damage小的放前面?Collections.sort也无法确定
所以要指定到底按照哪种属性进行排序
这里就需要提供一个Comparator给定如何进行两个对象之间的大小比较

package charactor;
 
public class Hero  {
    public String name;
    public float hp;
 
    public int damage;
 
    public Hero() {
 
    }
 
    public Hero(String name) {

        this.name = name;
    }
 
 	public String toString() {
		return "Hero [name=" + name + ", hp=" + hp + ", damage=" + damage + "]\r\n";
	}

	public Hero(String name, int hp, int damage) {
    	this.name = name;
    	this.hp = hp;
    	this.damage = damage;
	}
 
}




package collection;
    
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
   
import charactor.Hero;
    
public class TestCollection {
    public static void main(String[] args) {
        Random r =new Random();
        List<Hero> heros = new ArrayList<Hero>();
           
        for (int i = 0; i < 10; i++) {
            //通过随机值实例化hero的hp和damage
            heros.add(new Hero("hero "+ i, r.nextInt(100), r.nextInt(100)));
        }
        System.out.println("初始化后的集合:");
        System.out.println(heros);
           
        //直接调用sort会出现编译错误,因为Hero有各种属性
        //到底按照哪种属性进行比较,Collections也不知道,不确定,所以没法排
        //Collections.sort(heros);
           
        //引入Comparator,指定比较的算法
        Comparator<Hero> c = new Comparator<Hero>() {
            @Override
            public int compare(Hero h1, Hero h2) {
                //按照hp进行排序
                if(h1.hp>=h2.hp)
                    return 1;  //正数表示h1比h2要大
                else
                    return -1;
            }
        };
        Collections.sort(heros,c);
        System.out.println("按照血量排序后的集合:");
        System.out.println(heros);
    }
}

4.2.2 Comparable

使Hero类实现Comparable接口
在类里面提供比较算法
Collections.sort就有足够的信息进行排序了,也无需额外提供比较器Comparator
注: 如果返回-1, 就表示当前的更小,否则就是更大


package charactor;
   
public class Hero implements Comparable<Hero>{
    public String name; 
    public float hp;
      
    public int damage;
      
    public Hero(){
         
    }
     
    public Hero(String name) {
        this.name =name;
 
    }
     
    //初始化name,hp,damage的构造方法
    public Hero(String name,float hp, int damage) {
        this.name =name;
        this.hp = hp;
        this.damage = damage;
    }
 
    @Override
    public int compareTo(Hero anotherHero) {
        if(damage<anotherHero.damage)
            return 1;  
        else
        	return -1;
    }
 
    @Override
    public String toString() {
        return "Hero [name=" + name + ", hp=" + hp + ", damage=" + damage + "]\r\n";
    }
     
}





package collection;
  
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
 
import charactor.Hero;
  
public class TestCollection {
    public static void main(String[] args) {
        Random r =new Random();
        List<Hero> heros = new ArrayList<Hero>();
         
        for (int i = 0; i < 10; i++) {
            //通过随机值实例化hero的hp和damage
            heros.add(new Hero("hero "+ i, r.nextInt(100), r.nextInt(100)));
        }
         
        System.out.println("初始化后的集合");
        System.out.println(heros);
         
        //Hero类实现了接口Comparable,即自带比较信息。
        //Collections直接进行排序,无需额外的Comparator
        Collections.sort(heros);
        System.out.println("按照伤害高低排序后的集合");
        System.out.println(heros);
         
    }
}

4.3 聚合操作

JDK8之后,引入了对集合的聚合操作,可以非常容易的遍历,筛选,比较集合中的元素。

像这样:

    String name =heros
        .stream()
        .sorted((h1,h2)->h1.hp>h2.hp?-1:1)
        .skip(2)
        .map(h->h.getName())
        .findFirst()
        .get();

但是要用好聚合,必须先掌握Lambda表达式,聚合的章节讲放在Lambda与聚合操作部分详细讲解
在这里插入图片描述


package lambda;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

import charactor.Hero;
 
public class TestAggregate {
 
    public static void main(String[] args) {
        Random r = new Random();
        List<Hero> heros = new ArrayList<Hero>();
        for (int i = 0; i < 10; i++) {
            heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100)));
        }

        System.out.println("初始化集合后的数据 (最后一个数据重复):");
        System.out.println(heros);
        
        //传统方式
        Collections.sort(heros,new Comparator<Hero>() {
			@Override
			public int compare(Hero o1, Hero o2) {
				return (int) (o2.hp-o1.hp);
			}
		});
        
        Hero hero = heros.get(2);
        System.out.println("通过传统方式找出来的hp第三高的英雄名称是:" + hero.name);
        
        //聚合方式
        String name =heros
        	.stream()
        	.sorted((h1,h2)->h1.hp>h2.hp?-1:1)
        	.skip(2)
        	.map(h->h.getName())
        	.findFirst()
        	.get();

        System.out.println("通过聚合操作找出来的hp第三高的英雄名称是:" + name);
        
    }
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值