学习笔记5:JavaSE & API(集合 & Map)
1、集合综述
(1)定义:集合与数组一样,可以保存一组元素,并且提供了操作元素的相关方法,使用更方便。
(2)java集合框架中相关接口
- java.util.Collection接口:所有集合的顶级接口。Collection下面有多种实现类,因此我们有更多的数据结构可供选择。
- java.util.List:线性表。是可重复集合,并且有序。
- java.util.Set:不可重复的集合,大部分实现类是无序的。
(3)集合中的元素:集合不可以放基本类型(如果放基本类型会自动装箱),只可以放引用类型(地址)。
(4)元素重复的判定:依靠元素自身equals比较的结果,为true就认为是重复元素。默认equals比较的是地址。
2、java.util.Collection接口
(1)子接口:
- List:可重复且有序,常用实现类,ArrayList
- Set:不可重复,HashSet
(2)常用方法
- add():是有返回值的,添加成功返回true。
- size():返回集合的大小。
- isEmpty():是否为空。
- clear():清空集合内元素。
- contains(): 是否包含某元素,通过equals方法比较,默认是比较的地址。
- remove():删除某元素。对于list而言,重复元素只会删除一次。
(3)集合间的操作
- addAll():两集合取并集。当添加后的集合发生改变了,返回true。
- containsAll():判断是否包含所有元素。
- retainAll():两个集合取交集。
- removeAll():两个集合删交集。
3、集合的遍历
(1)迭代器模式:java.util.Iterator 迭代器接口。 Iterator iterator(), 该方法可以获取一个用于遍历当前集合的迭代器实现类。
- hasNext():判断是否有下一个,一定要先判断
- next():移动到下一个,并取出
- 示例
Collection c = new ArrayList(); c.add("one"); c.add("#"); c.add("two"); c.add("#"); c.add("three"); Iterator it = c.iterator(); //一定先判断,再取出,然后再操作 while(it.hasNext()){ String e = (String)it.next(); System.out.println(e); if("#".equals(e)){ //不可以直接用集合删除元素 it.remove(); } } System.out.println(c);
- 注意:
- 遍历过程中,不要通过集合的add、remove改变集合的元素个数。
- 遍历过程中,可以使用迭代器的remove的方法删除,但是迭代器没有add。
- Iteartor也是可以加泛型的。
(2)新循环遍历
- 说明:JDK5之后,推出了一个新的特性,增强型for循环.也称为新循环。是可以使用相同的语法遍历集合或数组。
- 语法:for(变量:集合){ }
(3)泛型:
- JDK5推出的新特性。也称作参数化类型,在使用一个类时去指定该类中某个属性的类型、方法返回值的类型、方法参数的类型。
- 泛型在集合中广泛使用,用于指定该集合中的元素类型。
- 集合中不指定泛型,默认是Object。
4、List集
(1)定义
- java.util.List接口,继承自Collection。
- List集合是可重复集,并且有序,提供了一套可以通过下标操作元素的方法。
(2)常用实现类
- java.util.ArrayList:连续空间、查询性能好、可重复、有序
- java.util.LinkedList:链表、增删性能好(首位增删性能最佳)
(3)常用方法
- get():通过下标访问元素
- set():设置某个位置的元素,同时,返回值是被替换下来的元素
- Collections.reverse():反转集合。Collections是集合的工具类,里面有很多静态方法。
- 重载add():在指定位置添加
- 重载remove():删除指定位置元素,同时,返回值是删除的元素
- subList():截取指定字符串,(a, b)含头不含尾。注意:对子集的操作,就是对原集合的操作。
- clear():清空集合
5、集合转换为数组
(1)Collection提供了一个方法:toArray,可以将当前集合转换为一个数组。
(2)toArray():传一个指定类型的数组进去,数组长度固定,返回指定类型的数组。
- 如果长度过大,则返回值数组的后面几位为null;
- 如果长度过小,则返回数组长度为集合内部数组的长度;
- 如果长度正好,则返回正常长度的数组。
List<String> list = new ArrayList<>(); list.add("one"); list.add("two"); list.add("three"); /* 重载的toArray方法要求传入一个数组,内部会将集合所有元素存入该数组后将其返回(前提是该数组长度>=集合的size)。 如果给定的数组长度不足,则方法内部会自行根据给定数组类型创建一个与集合size一致长度的数组并将集合元素存入后返回。 */ String[] array = list.toArray(new String[list.size()]); //其实可以直接写成传入长度0 // String[] array = list.toArray(new String[0]); System.out.println(array.length); System.out.println(Arrays.toString(array));
6、数组转换为List集合
(1)说明:数组的工具类Arrays提供了一个静态方法asList(),可以将一个数组转换为一个List集合。
(2)Arrays.asList(array):数组转成集合
- 对该集合的操作,就是对数组的操作,比如set
- 同时,一切改变数组长度的操作都是报错:UnsupportedOperationException,比如add和remove。
(3)new ArrayList(list):包含Collection的构造器,创建的ArrayList包含Collection的所有元素。Collection可以是list也可以是set,如果是set,注意它会去重。
String[] array = {"one","two","three","four","five"}; System.out.println("array:"+ Arrays.toString(array)); //方法一:asList,数组和集合是同一引用 List<String> list = Arrays.asList(array); System.out.println("list:" + list); //对该集合的操作就是对原数组对应的操作 list.set(1,"six"); System.out.println("list:" + list); System.out.println("array:"+ Arrays.toString(array)); //会改变数组长度的操作都是不支持的,因为数组是定长的。 //会抛出异常:java.lang.UnsupportedOperationException(不支持的操作异常) //list.add("seven"); //方法二:addAll List<String> list2 = new ArrayList<>(); list2.addAll(list); System.out.println("list2:"+list2); //方法三:所有的集合都支持一个参数为Collection的构造器,作用是在创建当前集合的同时包含给定集合中的所有元素 List<String> list3 = new ArrayList<>(list); list3.add("seven"); System.out.println("list3:"+list3);
7、集合的排序
(1)java.util.Collections类:集合的工具类,里面定义了很多静态方法用于操作集合。
(2)Collections.sort(list):自然排序,升序。
(3)Collections.shuffle(list):乱序。
(4)Collections.sort(list, comparator):使用Comparator比较器。
- Collections.sort(list):list的元素需要实现Comparable接口,重写compareTo()方法。
- Collections.sort(list, comparator):使用Comparator比较器,并实现compare方法。
/********************************** 自然排序 *********************************************/ List<Integer> list = new ArrayList<>(); Random random = new Random(); for(int i=0;i<10;i++){ list.add(random.nextInt(100)); } System.out.println(list); Collections.sort(list); System.out.println(list); /********************************** 自定义类型排序 *********************************************/ List<Point> list2 = new ArrayList<>(); list2.add(new Point(1,2)); list2.add(new Point(15,8)); list2.add(new Point(9,7)); System.out.println(list2); Collections.sort(list2,new Comparator<Point>() { @Override public int compare(Point o1, Point o2) {//compare:比较 int len1 = o1.getX()*o1.getX()+o1.getY()* o1.getY(); int len2 = o2.getX()*o2.getX()+o2.getY()* o2.getY(); return len1-len2; } }); //lambda写法 Collections.sort(list2,(o1,o2)-> o1.getX() * o1.getX() + o1.getY() * o1.getY() - o2.getX() * o2.getX() - o2.getY() * o2.getY() ); System.out.println(list);
8、Map 查找表
(1)定义:Map体现的结构是一个多行两列的表格,其中左列称为key,右列称为value。
- Map总是成对保存数据,并且总是根据key获取对应的value。可以将查询的条件作为key查询对应的结果作为value保存到Map中。
- Map有一个要求:key不允许重复(equals比较的结果)
(2)java.util.Map接口:是所有Map的顶级接口,规定了Map的相关功能。
(3)常用实现类:
- java.util.HashMap:称为散列表,使用散列算法实现的Map,当今查询速度最快的数据结构。
- java.util.TreeMap:使用二叉树实现的Map。
(4)常用方法:
- size():获取map长度
- put(k,v):将一个键值对存入map
- 如果使用重复的key存入value,则是替换value操作,此时put方法的返回值就是被替换的value。否则返回值为null。
- 如果value的类型是包装类,切记不要用基本类型接收返回值,避免因为自动拆箱导致的空指针。
- get(Object key)
- remove(Object key):删除给定的key所对应的键值对,返回值为这个key对应的value。
- containsKey(Object key)
- containsValue(Object value)
- keySet():获取所有key。将当前Map中所有的key以一个Set集合形式返回,遍历该集合等同于遍历所有的key。
- entrySet():获取所有键值对
- 将当前Map中每一组键值对以一个Entry实例形式表示,并存入Set集合后返回。
- java.util.Map.Entry的每一个实例用于表示Map中的一组键值对,其中方法:K getKey():获取对应的key,V getValue():获取对应的value。
-
values():获取所有值。将当前Map中所有的value以一个集合形式返回(Collection)
(5)示例:
Map<String,Integer> map = new HashMap<>(); map.put("语文",99); map.put("数学",98); map.put("英语",97); //获取map长度 int size = map.size(); System.out.println("size:"+size); //获取某个值 Integer score = map.get("语文"); System.out.println("语文:"+score); //判断包含:key 或 value boolean ck = map.containsKey("语文"); System.out.println("包含key:"+ck); boolean cv = map.containsValue(99); System.out.println("包含value:"+cv); //删除键值对,返回值为该key对应的value Integer value = map.remove("语文"); System.out.println("删除后" + map); System.out.println("删除的值" + value);
9、Map 的遍历
(1)遍历的方式
- 遍历所有的key
- 遍历所有的键值对
- 遍历所有的value(相对不常用)
- forEach:lambda表达式遍历
(2)代码示例
public static void main(String[] args) { Map<String,Integer> map = new HashMap<>(); map.put("语文",99); map.put("数学",98); map.put("英语",97); /************************************* 普通遍历 ****************************************/ //获取所有键值对 Set<Map.Entry<String,Integer>> entrySet = map.entrySet(); for(Map.Entry<String,Integer> e : entrySet){ String key = e.getKey(); Integer value1 = e.getValue(); System.out.println(key+":"+value1); } //获取所有key Set<String> keySet = map.keySet(); for(String key : keySet){ System.out.println("遍历 key:"+key); } //获取所有值 Collection<Integer> values = map.values(); for(Integer value2 : values){ System.out.println("遍历 value:"+value2); } /************************************* forEach ****************************************/ //集合的forEach Collection<String> c = new ArrayList<>(); c.add("one"); c.add("two"); c.add("three"); c.forEach(s->System.out.println(s)); //Map的forEach map.forEach((k,v)-> System.out.println(k+":"+v)); /******************************* forEach解析:BiConsumer类型的参数 ***********************************/ /* * BiConsumer<R, T> 是一个函数式接口,它接受两个参数并且没有返回值。 * 其中,R 和 T 是参数的类型。 * May的forEach接收的是BiConsumer类型参数 * */ //1、完整代码:遍历键值对,主动调用accept BiConsumer<String,Integer> action = new BiConsumer<String, Integer>() { public void accept(String k, Integer v) { System.out.println("完整写法"+k+":"+v); } }; Set<Map.Entry<String,Integer>> entrySet1 = map.entrySet(); for(Map.Entry<String,Integer> e : entrySet1) { String k = e.getKey(); Integer v = e.getValue(); action.accept(k,v); } //2、Map的forEach方法的回调写法 BiConsumer<String,Integer> action1 = new BiConsumer<String, Integer>() { public void accept(String k, Integer v) { System.out.println("使用forEach"+k+":"+v); } }; map.forEach(action1); //3、简写:使用lambda表达式形式创建 BiConsumer<String,Integer> action2 = (k,v)->System.out.println("lambda:"+k+":"+v); map.forEach(action2); //4、简写:最终写法 map.forEach((k,v)->System.out.println("最终写法:"+k+":"+v)); }