day-2-4-5

TreeMap

特点
  • TreeMap 是一个有序的key-value集合,它是通过红黑树实现的。
  • TreeMap 继承于AbstractMap,所以它是一个Map,即一个key-value集合。
  • TreeMap 实现了NavigableMap接口,意味着它支持一系列的导航方法。比如返回有序的key集合。TreeMap
  • 实现了Cloneable接口,意味着它能被克隆。
  • TreeMap 实现了java.io.Serializable接口,意味着它支持序列化。
  • TreeMap基于红黑树(Red-Black tree)实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的Comparator 进行排序,具体取决于使用的构造方法。
  • TreeMap的基本操作 containsKey、get、put 和 remove 的时间复杂度是 log(n) 。
  • 另外,TreeMap是非同步的。 它的iterator 方法返回的迭代器是fail-fastl的。
总结

1.由于TreeMap中的元素是从小到大的顺序排列的。因此,顺序遍历,就是从第一个元素开始,逐个向后遍历;而倒序遍历则恰恰相反,它是从最后一个元素开始,逐个往前遍历。

2.TreeMap基于红黑树(Red-Black tree)实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。

3.TreeMap的基本操作 containsKey、get、put 和 remove 的时间复杂度是 log(n)。

TreeMap和HashMap的区别
  • HashMap是通过hashcode()对其内容进行快速查找的;HashMap中的元素是没有顺序的;
  • TreeMap中所有的元素都是有某一固定顺序的,如果需要得到一个有序的结果,就应该使用TreeMap;
  • HashMap继承AbstractMap类;覆盖了hashcode() 和equals() 方法,以确保两个相等的映射返回相同的哈希值;
  • TreeMap继承SortedMap类;他保持键的有序顺序;
  • HashMap:基于hash表实现的;使用HashMap要求添加的键类明确定义了hashcode() 和equals() (可以重写该方法);为了优化HashMap的空间使用,可以调优初始容量和负载因子;
  • TreeMap:基于红黑树实现的;TreeMap就没有调优选项,因为红黑树总是处于平衡的状态;
  • HashMap:适用于Map插入,删除,定位元素;
  • TreeMap:适用于按自然顺序或自定义顺序遍历键(key);

Java集合的快速失败机制 fail-fast

是java集合的一种错误检测机制,当多个线程对集合进行结构上的改变的操作时,有可能会产生 fail-fast 机制。

例如:假设存在两个线程(线程1、线程2),线程1通过Iterator在遍历集合A中的元素,在某个时候线程2修改了集合A的结构(是结构上面的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出ConcurrentModificationException 异常,从而产生fail-fast机制。

原因

迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount变量。集合在被遍历期间如果内容发生变化,就会改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值,是的话就返回遍历;否则抛出异常,终止遍历。

解决办法
  1. 在遍历过程中,所有涉及到改变modCount值得地方全部加上synchronized。

  2. 使用CopyOnWriteArrayList来替换ArrayList

ArrayList中的具体实现
 public Iterator<E> iterator() {
        return new Itr();
    }
 
 Itr类是ArrayList中针对Iterator接口的内部实现类
 private class Itr implements Iterator<E> {
     int cursor;       // index of next element to return
     int lastRet = -1; // index of last element returned; -1 if no such
     int expectedModCount = modCount; //是缓存的获取Itr对象时ArrayList中的modCount值
     
  public E next() {   //是调用iterator.next获取下一元素时所调用的方法
         checkForComodification();
         ......
  }  
     
  当前的修改次数是否等于缓存的修改次数,如果不相等则通过抛出运行时异常阻止后续程序的执行
 final void checkForComodification() {
         if (modCount != expectedModCount)
             throw new ConcurrentModificationException();
 }     
}

总结

1、所有集合类都位于java.util包下。Java的集合类主要由两个接口派生而出:Collection和Map,
Collection和Map是Java集合框架的根接口,这两个接口又包含了一些子接口或实现类。

2、集合接口:6个接口(短虚线表示),表示不同集合类型,是集合框架的基础。
Collection List Set Queue Map Comparable Comparator Iterable Iterator

3、抽象类:5个抽象类(长虚线表示),对集合接口的部分实现。可扩展为自定义集合类。
AbstractList AbstractSet AbstractMap …

4、实现类:8个实现类(实线表示),对接口的具体实现。
ArrayList LinkedList HashSet TreeSet HashMap TreeMap Stack PriorityQueue
Vector LinkedHashSet Hashtable LinkedHashMap

5、Collection 接口是一组无序并允许重复的对象。

6、Set 接口继承 Collection,集合元素无序且不重复。
hashCode和equals

7、List接口继承 Collection,允许重复,维护元素插入顺序。

8、Map接口是键-值对象,与Collection接口没有什么关系。

9、Set、List和Map可以看做集合的三大类:

- List集合是有序集合,集合中的元素可以重复,访问集合中的元素可以根据元素的索引来访问。
- Set集合是无序集合,集合中的元素不可以重复,访问集合中的元素只能根据元素本身来访问(也是集合里元素不允许重复的原因)。
- Map集合中保存Key-value对形式的元素,访问时只能根据每项元素的key来访问其value。

10、遍历集合中的对象,Iterable iterator ListIterator[双向遍历]

特殊的迭代器(走访器)Enumeration属于已经不建议使用的方法

@since   1.0
public interface Enumeration<E>

Enumeration<Integer> enu = list.elements();
while(enu.hasMoreElements()) {
	Integer obj=enu.nextElement();
	System.out.println(obj);
}

11、看Arrays和Collections。它们是操作数组、集合的两个工具类

流式编程 stream

Stream中文称为流,通过将集合转换为这么一种叫做流的元素序列,通过声明性方式,能够对集合中的每个元素进行一系列并行或串行的流水线操作

Java 8中的Stream是对集合Collection对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作或者大批量数据操作。

Stream API借助于同样新出现的Lambda表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用fork/join并行方式来拆分任务和加速处理过程。通常编写并行代码很难而且容易出错, 但使用Stream API无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。所以Java 8 中首次出现的 java.util.stream 是一个函数式语言+多核时代综合影响的产物

Stream不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的Iterator。原始版本的Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;高级版本的Stream,用户只要给出需要对其包含的元素执行什么操作,比如过滤掉长度大于10的字符串、获取每个字符串的首字母等,Stream会隐式地在内部进行遍历,做出相应的数据转换。Stream就如同一个迭代器Iterator,单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。

而和迭代器又不同的是,Stream可以并行化操作,迭代器只能命令式地、串行化操作。顾名思义,当使用串行方式去遍历时,每个item读完后再读下一个item。而使用并行去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。Stream的并行操作依赖于Java7中引入的Fork/Join框架(JSR166y)来拆分任务和加速处理过程。Stream 的另外一大特点是,数据源本身可以是无限的。

Stream 的另外一大特点是,数据源本身可以是无限的。

当使用一个流的时候,通常包括三个基本步骤:获取一个数据源source → 数据转换 → 执行操作获取想要的结果。每次转换原有Stream对象不改变,返回一个新的Stream对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道

使用Stream步骤
  1. 创建Stream;
    • 创建方法1:可以使用Arrays.stream()方法来使用Stream

      Integer[] array = new Integer[]{3,4,8,16,19,27,23,99,76,232,33,96};
      long count = Arrays.stream(array).filter(i->i>20).count();

      Collection.parallelStream使用并行流提高性能,处理任务时并行处理,前提是硬件支持,如果单核CPU,只会存在并发处理而不会并行

      • ParallelStream在使用上与Stream无区别,本质返回的都是一个流,只不过底层处理时根据条件判断是并行或者是串行
      • 并行流并不会按照原本的顺序轨迹执行,而是随机执行,当然对于forEach输出也可以做到顺序串行
    • 创建方法2: 使用List创建一个并行流对象Stream

      Stream stream = list.parallelStream();

    • 创建方法3:Collection.stream()用Java集合都创建一个Stream
  2. 对Stream进行聚合(Reduce)操作,获取想要的结果;

流的转换

操作符就是对数据进行的一种处理工作,一道加工程序;就好像工厂的工人对流水线上的产品进行一道加工程序一样。Stream的操作符大体上分为两种:中间操作符和终止操作符

  • 对于数据流来说,中间操作符在执行制定处理程序后,数据流依然可以传递给下一级的操作符

    • map(mapToInt,mapToLong,mapToDouble) 转换操作符,把比如A->B,这里默认提供了转int,long,double的操作符
    • flatmap(flatmapToInt,flatmapToLong,flatmapToDouble) 拍平操作,比如把 int[]{2,3,4} 拍平变成 2,3,4 也就是从原来的一个数据变成了3个数据,这里默认提供了拍平成int,long,double的操作符
    • limit 限流操作,比如数据流中有10个只要出前3个就可以使用
    • distint 去重操作,对重复元素去重,底层使用了equals方法
    • filter 过滤操作,把不想要的数据过滤
    • peek 挑出操作,如果想对数据进行某些操作,如:读取、编辑修改等
    • skip 跳过操作,跳过某些元素
    • sorted(unordered) 排序操作,对元素排序,前提是实现Comparable接口,当然也可以自定义比较器。
  • 数据经过中间加工操作,就轮到终止操作符上场了;终止操作符就是用来对数据进行收集或者消费的,数据到了终止操作这里就不会向下流动了,终止操作符只能使用一次

    • collect 收集操作,将所有数据收集起来,这个操作非常重要,官方的提供的Collectors 提供了非常多收集器,可以说Stream 的核心在于Collectors
    • count 统计操作,统计最终的数据个数
    • findFirst、findAny 查找操作,查找第一个、查找任何一个 返回的类型为Optional
    • noneMatch、allMatch、anyMatch 匹配操作,数据流中是否存在符合条件的元素 返回值为bool 值
    • min、max 最值操作,需要自定义比较器,返回数据流中最大最小的值
    • reduce 规约操作,将整个数据流的值规约为一个值,count、min、max底层就是使用reduce
    • forEach、forEachOrdered 遍历操作,这里就是对最终的数据进行消费了
    • toArray 数组操作,将数据流的元素转换成数组。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值