Java中级/集合框架2

集合框架-二叉树

二叉树由各种节点组成
二叉树特点:
每个节点都可以有左子节点,右子节点
每一个节点都有一个值
在这里插入图片描述
二叉树定义:

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次,才能找到对应的英雄。

测试逻辑:

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

2.HashMap的性能表现
使用HashMap 做同样的查找

  1. 初始化2000000个对象到HashMap中。
  2. 进行10次查询
  3. 统计每一次的查询消耗的时间
    可以观察到,几乎不花时间,花费的时间在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的数据是不能重复的,相同数据不能保存在一起,到底如何判断是否是重复的呢?

根据HashSetHashMap的关系,我们了解到因为HashSet没有自身的实现,而是里面封装了一个HashMap,所以本质上就是判断HashMapkey是否重复。
再通过上一步的学习,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表达式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值