其他集合框架
集合框架-二叉树
二叉树由各种节点组成
二叉树特点:
每个节点都可以有左子节点,右子节点
每一个节点都有一个值
二叉树定义:
package collection;
public class Node {
// 左子节点
public Node leftNode;
// 右子节点
public Node rightNode;
// 值
public Object value;
}
二叉树排序-插入数据(对应数据结构二叉排序树):
假设通过二叉树对如下10个随机数进行排序
67,7,30,73,10,0,78,81,10,74
排序的第一个步骤是把数据插入到该二叉树中
插入基本逻辑是,小、相同的放左边,大的放右边
二叉排序树实现:(不断递归的过程)
变量分成员变量 和局部变量 成员变量是指这个类的变量,局部变量是类中方法体内定义的变量。
成员变量定义: 定义在类中,被默认初始化,分为类成员变量和实力成员变量
在类内部,任何地方都可以访问成员变量
object包含的java的所有数据类型,所以如果定义了一个object类型的变量可以将任意类型的值给他
package collection;
public class Node {
// 左子节点
public Node leftNode;
// 右子节点
public Node rightNode;
// 值
public Object value;
// 插入 数据
public void adds(Object v) {
// 如果当前节点没有值,就把数据放在当前节点上
if (null == value)
value = v;
// 如果当前节点有值,就进行判断,新增的值与当前值的大小关系
else {
// 新增的值,比当前值小或者相同
if ((Integer) v -((Integer)value) <= 0) {
if (null == leftNode)
leftNode = new Node();
leftNode.adds(v);//不断递归的过程
}
// 新增的值,比当前值大
else {
if (null == rightNode)
rightNode = new Node();
rightNode.adds(v);
}
}
}
public static void main(String[] args) {
int randoms[] = new int[] { 67, 7, 30, 73, 10, 0, 78, 81, 10, 74 };
Node roots = new Node();
for (int number : randoms) {
roots.adds(number);
}
}
}
二叉树排序-遍历:
==通过上一个步骤的插入行为,实际上,数据就已经排好序了。 ==接下来要做的是看,把这些已经排好序的数据,遍历成我们常用的List或者数组的形式。
(遍历方式如同数据结构,分为先序/中序/后续)
中序遍历:
// 中序遍历所有的节点
public List<Object> values() {
List<Object> values = new ArrayList<>();
// 左节点的遍历结果
if (null != leftNode)
values.addAll(leftNode.values());
// 当前节点
values.add(value);//调用的是数组的add方法
// 右节点的遍历结果
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 };
Node roots = new Node();
for (int number : randoms) {
roots.adds(number);
}
System.out.println(roots.values());
}
}
'输出:'
[0, 7, 10, 10, 30, 67, 73, 74, 78, 81]
练习-英雄二叉树
根据上面的学习和理解,设计一个Hero二叉树,HeroNode.
可以向这个英雄二叉树插入不同的Hero对象,并且按照Hero的血量倒排序
。
随机生成10个Hero对象,每个Hero对象都有不同的血量值,插入这个HeroNode后,把排序结果打印出来。
'第一种:'
package j2se;
import java.util.ArrayList;
import java.util.List;
public class HeroNode {
public HeroNode leftNode;
public HeroNode rightNode;
Hero hr;
public void adds(Hero t){
if (null == hr){
hr = t;
}else {
if(t.hp-hr.hp<=0){
if(null==leftNode)
leftNode = new HeroNode();
leftNode.adds(t);
}else if(t.hp-hr.hp>=0){
if(null==rightNode)
rightNode = new HeroNode();
rightNode.adds(t);
}
}
}
public List<Hero> values(){
ArrayList<Hero> ls = new ArrayList<>();
if(null!=rightNode){
ls.addAll(rightNode.values());
}
ls.add(this.hr);
if(null!=leftNode){
ls.addAll(leftNode.values());
}
return ls;
}
public static void main(String[] args){
HeroNode HeroRoots = new HeroNode();
for (int i = 0;i<10;i++){
Hero h = new Hero("hero"+i);
h.hp = (float)(Math.random()*1000);
System.out.println(h);
HeroRoots.adds(h);
//System.out.println(HeroRoots.values());
}
ArrayList<Hero> ln = (ArrayList<Hero>) HeroRoots.values();
for(Hero l:ln){
System.out.println("英雄名:"+l.name+"血量值为: "+l.hp);
}
}
}
‘第二种:’
package collection;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class HeroTree {
public HeroTree leftNode;
public HeroTree rightNode;
public Hero t;
public void adds(Hero h){
if (t==null){
t = h;
}
else{
if(t.hp-h.hp<=0){
if(leftNode==null)
leftNode = new HeroTree();
leftNode.adds(h);
}else {
if (null == rightNode)
rightNode = new HeroTree();
rightNode.adds(h);
}
}
}
public static void inTraverBinaryTree(HeroTree tree){
if (tree==null) return;
if (tree.leftNode !=null){
inTraverBinaryTree(tree.leftNode);
}
System.out.println("name:"+tree.t.name+",hp:"+tree.t.hp);
if(tree.rightNode != null){
inTraverBinaryTree(tree.rightNode);
}
}
public static void main(String[] args) {
Random r = new Random();
List<Hero> heroNode = new ArrayList<>();
HeroTree heroTree = new HeroTree();
System.out.println("初始化10个Hero");
for (int i = 0;i<10;i++){
heroNode.add(new Hero("英雄"+i,r.nextFloat()*300));
System.out.println("name:"+heroNode.get(i).name+",hp:"+heroNode.get(i).hp);
}
for (Hero h :heroNode){
heroTree.adds(h);
}
System.out.println("中序遍历英雄树:");
inTraverBinaryTree(heroTree);
}
}
HashMap
HashMap的键值对(键不能重复,值可以重复 )
HashMap存储数据的方式是----键值对
package collection;
import java.util.HashMap;
public class TestCollection {
public static void main(String[] args) {
HashMap<String,String> dictionary = new HashMap<>();
dictionary.put("adc", "物理英雄");
dictionary.put("apc", "魔法英雄");
dictionary.put("t", "坦克");
System.out.println(dictionary.get("t"));
}
}
对于HashMap而言,key是唯一的,不可以重复的。
所以,以相同的key 把不同的value插入到 Map中会导致旧元素被覆盖,只留下最后插入的元素。不过,同一个对象可以作为值插入到map中,只要对应的key不一样
package collection;
import java.util.HashMap;
import charactor.Hero;
public class TestCollection {
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放入数据,会导致原英雄,被覆盖
//不会增加新的元素到Map中
heroMap.put("gareen", new Hero("gareen2"));
System.out.println(heroMap);
//清空map
heroMap.clear();
Hero gareen = new Hero("gareen");
//同一个对象可以作为值插入到map中,只要对应的key不一样
heroMap.put("hero1", gareen);
heroMap.put("hero2", gareen);
System.out.println(heroMap);
}
}
HashSet
实现
Set中的元素,不能重复
package collection;
import java.util.HashSet;
public class TestCollection {
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);
}
}
没有顺序
Set中的元素,没有顺序。
严格的说,是没有按照元素的插入顺序排列。HashSet的具体顺序,既不是按照插入顺序,也不是按照hashcode的顺序
换句话说,同样是插入0-9到HashSet中, 在JVM的不同版本中,看到的顺序都是不一样的。
package collection;
import java.util.HashSet;
public class TestCollection {
public static void main(String[] args) {
HashSet<Integer> numbers = new HashSet<Integer>();
numbers.add(9);
numbers.add(5);
numbers.add(1);
// Set中的元素排列,不是按照插入顺序
System.out.println(numbers);
}
}
遍历
Set不提供get()来获取指定位置的元素
所以遍历需要用到迭代器,或者增强型for循环
package collection;
import java.util.HashSet;
import java.util.Iterator;
public class TestCollection {
public static void main(String[] args) {
HashSet<Integer> numbers = new HashSet<Integer>();
for (int i = 0; i < 20; i++) {
numbers.add(i);
}
//Set不提供get方法来获取指定位置的元素
//numbers.get(0)
//遍历Set可以采用迭代器iterator
for (Iterator<Integer> iterator = numbers.iterator(); iterator.hasNext();) {
Integer i = (Integer) iterator.next();
System.out.println(i);
}
//或者采用增强型for循环
for (Integer i : numbers) {
System.out.println(i);
}
}
}
HashSet和HashMap的关系
通过观察HashSet的源代码,可以发现HashSet自身并没有独立的实现,而是在里面封装了一个Map
.
HashSet
是作为Map
的key而存在的
而value
是一个命名为PRESENT
的static的Object对象,因为是一个类属性
,所以只会有一个。
private static final Object PRESENT = new Object();
package collection;
import java.util.AbstractSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{
//HashSet里封装了一个HashMap
private HashMap<E,Object> map;
private static final Object PRESENT = new Object();
//HashSet的构造方法初始化这个HashMap
public HashSet() {
map = new HashMap<E,Object>();
}
//向HashSet中增加元素,其实就是把该元素作为key,增加到Map中
//value是PRESENT,静态,final的对象,所有的HashSet都使用这么同一个对象
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
//HashSet的size就是map的size
public int size() {
return map.size();
}
//清空Set就是清空Map
public void clear() {
map.clear();
}
//迭代Set,就是把Map的键拿出来迭代
public Iterator<E> iterator() {
return map.keySet().iterator();
}
}
练习
创建一个长度是100的字符串数组
使用长度是2的随机字符填充该字符串数组
统计这个字符串数组里重复的字符串有多少种
使用HashSet来解决这个问题
package collection;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Random;
/**
* 创建一个长度是100的字符串数组
* 使用长度是2的随机字符填充该字符串数组
* 统计这个字符串数组里重复的字符串有多少种
* 数字:48~57
* 大写字母:65~65+26,小写97~97+26
*/
public class HashSetTest {
public static void main(String[] args) {
HashSet<String> hashSet = new HashSet<>();
String[] str = new String[100];
Random random = new Random();
char[] ch = new char[2];
for (int i = 0; i < str.length; i++) {
for (int j = 0; j < 2; j++) {
//判断获取的是数字还是字母,数字概率是10/62,字母概率52/62
if(random.nextInt(62) > 10){
//判断大小写
if(random.nextInt(2)%2 == 0){
ch[j] = (char)(random.nextInt(26) + 65);
}
else
ch[j] = (char)(random.nextInt(26) + 97);
}else {
ch[j] = (char)(random.nextInt(10) + 48);
}
}
str[i] = String.valueOf(ch);
}
System.out.println(Arrays.toString(str));
for (int i = 0; i < str.length; i++) {
//add()如果没有重复将加入集合,并且返回true
if(!hashSet.add(str[i])){
System.out.println(str[i]);
}
}
}
}
Collection是一个接口
Collection是 Set、 List 、Queue和 Deque
的接口。(接口只能继承接口,不能实现,继承接口后可以增加新的方法)
Queue: 先进先出队列
Deque: 双向链表
源码:
public interface Deque<E> extends Queue<E>
public interface Queue<E> extends Collection<E>
public interface Collection<E> extends Iterable<E>
注:Collection和Map之间没有关系,Collection是放一个一个对象的,Map 是放键值对的。
注:Deque 继承 Queue,间接的继承了 Collection 。
## Collections
Collections是一个类,容器的工具类,就如同Arrays是数组的工具类
反转(reverse)/shuffle/sort/swap/rotate/synchronizedList
reverse 使List中的数据发生翻转
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);//翻转后集合中的数据****
Collections.shuffle(numbers);//混淆后集合中的数据
Collections.sort(numbers);//排序
Collections.swap(numbers,0,5);//交换0和5下标的数据
//rotate 把List中的数据,向右滚动指定单位的长度
Collections.rotate(numbers,2);//把集合向右滚动2个单位
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);
}
}
集合框架关系与区别
ArrayList vs HashSet
是否有顺序:
ArrayList
: 有顺序
HashSet
: 无顺序
不保证Set的迭代顺序; 确切的说,在不同条件下,元素的顺序都有可能不一样
换句话说,同样是插入0-9到HashSet中, 在JVM的不同版本中,看到的顺序都是不一样的。 所以在开发的时候,不能依赖于某种臆测的顺序,这个顺序本身是不稳定的
能否重复
List
中的数据可以重复
Set
中的数据不能够重复
重复判断标准是:
首先看hashcode
是否相同
如果hashcode
不同,则认为是不同数据
如果hashcode
相同,再比较equals
,如果equals
相同,则是相同数据,否则是不同数据
package collection;
import java.util.ArrayList;
import java.util.HashSet;
public class TestCollection {
public static void main(String[] args) {
ArrayList<Integer> numberList =new ArrayList<Integer>();
//List中的数据可以重复
System.out.println("----------List----------");
System.out.println("向List 中插入 9 9");
numberList.add(9);
numberList.add(9);
System.out.println("List 中出现两个9:");
System.out.println(numberList);
System.out.println("----------Set----------");
HashSet<Integer> numberSet =new HashSet<Integer>();
System.out.println("向Set 中插入9 9");
//Set中的数据不能重复
numberSet.add(9);
numberSet.add(9);
System.out.println("Set 中只会保留一个9:");
System.out.println(numberSet);
}
}
ArrayList VS LinkedList
ArrayList和LinkedList的区别
ArrayList
插入,删除数据慢
LinkedList
, 插入,删除数据快
ArrayList是顺序结构,所以定位很快,指哪找哪。 就像电影院位置一样,有了电影票,一下就找到位置了。
LinkedList
是链表结构,就像手里的一串佛珠,要找出第99个佛珠,必须得一个一个的数过去,所以定位慢
插入数据比较
package collection;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class TestCollection {
public static void main(String[] args) {
List<Integer> l;
l = new ArrayList<>();
insertFirst(l, "ArrayList");
l = new LinkedList<>();
insertFirst(l, "LinkedList");
}
private static void insertFirst(List<Integer> l, String type) {
int total = 1000 * 100;
final int number = 5;
long start = System.currentTimeMillis();
for (int i = 0; i < total; i++) {
l.add(0, number);
}
long end = System.currentTimeMillis();
System.out.printf("在%s 最前面插入%d条数据,总共耗时 %d 毫秒 %n", type, total, end - start);
}
}
HashMap VS HashTable
HashMap和Hashtable的区别 :
HashMap和Hashtable都实现了Map接口,都是键值对保存数据的方式
区别1:
HashMap可以存放 null
Hashtable不能存放null
区别2:
HashMap不是线程安全的类
Hashtable是线程安全的类
其他几种set
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);
}
}
hashcode的原理
1.List查找的低效率
假设在List中存放着无重复名称,没有顺序的2000000个Hero 要把名字叫做
“hero 1000000”
的对象找出来
List
的做法是对每一个进行挨个遍历,直到找到名字叫做“hero 1000000”
的英雄。
最差的情况下,需要遍历和比较2000000
次,才能找到对应的英雄。
测试逻辑:
- 初始化2000000个对象到ArrayList中
- 打乱容器中的数据顺序
- 进行10次查询,统计每一次消耗的时间
不同计算机的配置情况下,所花的时间是有区别的。 在本机上,花掉的时间大概是600毫秒左右
2.HashMap的性能表现
使用HashMap 做同样的查找
- 初始化2000000个对象到HashMap中。
- 进行10次查询
- 统计每一次的查询消耗的时间
可以观察到,几乎不花时间,花费的时间在1毫秒以内
package collection;
import java.util.HashMap;
import charactor.Hero;
public class TestCollection {
public static void main(String[] args) {
HashMap<String,Hero> heroMap = new HashMap<String,Hero>();
for (int j = 0; j < 2000000; j++) {
Hero h = new Hero("Hero " + j);
heroMap.put(h.name, h);
}
System.out.println("数据准备完成");
for (int i = 0; i < 10; i++) {
long start = System.currentTimeMillis();
//查找名字是Hero 1000000的对象
Hero target = heroMap.get("Hero 1000000");
System.out.println("找到了 hero!" + target.name);
long end = System.currentTimeMillis();
long elapsed = end - start;
System.out.println("一共花了:" + elapsed + " 毫秒");
}
}
}
==HashMap原理与字典 ==
在展开HashMap原理的讲解之前,首先回忆一下大家初中和高中使用的汉英字典。
比如要找一个单词对应的中文意思,假设单词是Lengendary,首先在目录找到Lengendary在第 555页。
然后,翻到第555页,这页不只一个单词,但是量已经很少了,逐一比较,很快就定位目标单词Lengendary。
555相当于就是Lengendary对应的hashcode
分析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进行查询,非常快原理。
这是一种用空间换时间的思维方式
HashSet判断是否重复
HashSet的数据是不能重复的,相同数据不能保存在一起,到底如何判断是否是重复的呢?
根据
HashSet
和HashMap
的关系,我们了解到因为HashSet
没有自身的实现,而是里面封装了一个HashMap
,所以本质上就是判断HashMap
的key
是否重复。
再通过上一步的学习,key
是否重复,是由两个步骤判断的:hashcode
是否一样
如果hashcode
不一样,就是在不同的坑里,一定是不重复的 如果hashcode
一样,就是在同一个坑里,还需要进行equals
比较
如果equals
一样,则是重复数据 如果equals
不一样,则是不同数据。
比较器
Comparator
假设Hero有三个属性 name,hp,damage
一个集合中放存放10个Hero,通过Collections.sort对这10个进行排序
那么到底是hp小的放前面?还是damage小的放前面?Collections.sort也无法确定
直接调用sort会出现编译错误,因为Hero有各种属性
到底按照哪种属性进行比较,Collections也不知道,不确定,所以没法排
Collections.sort(heros);
所以要指定到底按照哪种属性进行排序
这里就需要提供一个Comparator给定如何进行两个对象之间的大小比较
'Hero.java'
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;
}
}
TestCollection.java
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);
}
}
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);
}
}
聚合操作
JDK8之后,引入了对集合的聚合操作,可以非常容易的遍历,筛选,比较集合中的元素。
像这样:
String name =heros
.stream()
.sorted((h1,h2)->h1.hp>h2.hp?-1:1)
.skip(2)
.map(h->h.getName())
.findFirst()
.get();
但是要用好聚合,必须先掌握Lambda表达式