黑马程序员技术交流社区

标题: [石家庄校区] JAVA_List_Set_Map_异常_线程 [打印本页]

作者: 13333114253    时间: 2018-11-17 19:30
标题: [石家庄校区] JAVA_List_Set_Map_异常_线程
本帖最后由 13333114253 于 2018-11-20 11:16 编辑

01-数据结构
             就是数据的存储方式
      1).栈:   先进后出 (FILO, First In Last Out)          入口和出口在同一侧
             入栈(压栈): 将元素存入栈
              出栈(弹栈): 从栈中取出元素
      2).对列:  先进先出 (FIFO, First In First Out)         入口和出口在两端

      3).数组:  
               查询快: 通过 (第一个元素地址值 + 索引) 可以快速计算出该索引元素的地址值
               增删慢: 增加一个元素, 要创建长度+1的新数组, 然后将原数组元素复制到新数组, 然后存入新元素; 删除类似

      4).链表:
               查询慢: 要找到其中某个节点, 只能从第一个节点一个一个向后寻找
               增删快: 只需要修改保存的下一个节点的地址值, 就可以快速完成增删

       5).红黑树:
                            平衡 二叉 查找 树
                  平衡: 左子节点和右子节点数量相等
                  二叉: 每个节点最多有2个子节点
                  查找: 节点存储的元素是按照大小顺序存储的
        特点:
                  元素存储过程中就完成了大小排序
                  查询比链表快, 增删比数组快 (数组和链表的折中)

02-List集合
          特点:有序集合、带索引、可以有重复的元素、可以用equals方法判断
     2.1). 常用方法
               List<E> list = new ArrayList<>();
                     list.add(int  index, E e);//添加到指定位置
                     list.get(int index);//返回指定位置的元素
                     list.remove(int remove);//删除指定位置的元素
                     list.set(int index,E e);//替换指定位置的元素,并更新集合

      2.2). ArrayList集合
                   底层的数 据结构:数组
             特点: 查询快  增删慢 线程不安全, 效率高
       2.3). LinkedList 集合
                    底层的数据结构:链表
             特点:  查询  增删 线程不安全, 效率高
         特有成员方法(主要操作开头和末尾元素)
               java.util.LinkedList<E>类:
              List<E> list = new LinkedList<>();
              list.addFirst(E e); //将指定元素插入此列表的开头
              
list.addLast(E e);// 将指定元素添加到此列表的结尾
              
list.getFirst(); //返回此列表的第一个元素
              
list.getLast(); //返回此列表的最后一个元素
              
list.removeFirst(); //移除并返回此列表的第一个元素
              
list.removeLast(); //移除并返回此列表的最后一个元素
              
list.pop();// 其实就是removeFirst())从此列表所表示的栈中弹出一个元素
              
list.push(E e); //其实就是addFirst())将元素添加到此列表所表示的栈中
      2.4).Vector集合 (几乎不用)
                     底层的数据结构: 数组
               特点:      查询慢    增删快   (同步)线程安全, 效率低

03-Set集合体系
         3.1). HashSet集合
               1).Set集合体系特点:
                  元素不可重复     没有索引
              2)HashSet特点:
                    元素不可重复 没有索引 元素存取无序 (存入和取出顺序有可能不一致)
                    底层采用 哈希表 结构. (查询快)
                    哈希表 = 数组 + 链表或红黑树
             3).常用方法
                    Set<E> set = new HashSet<>();
                      set.add();//添加元素      元素的 hashCode() 和 equals() 方法判断是否重复. 重复则不添加并返回false,
                                不重复则添加并返回true
                     hashCode() 方法的作用:有可能将"不同的对象"计算出"相同的哈希值", 这称为"哈希冲突", 在出现冲突后,
                     一般再通过equals() 方法来继续判断对象是否"相等"
             4).HashSet原理: 哈希表结构
                  哈希表:
                    JDK 8以前   : 哈希表 = 数组 + 链表
                    JDK 8及之后 : 哈希表 = 数组 + 链表或红黑树
                    数组中存储的每个元素, 是哈希值相同的一组节点的链表或红黑树
             5).HashSet原理: 存储元素不重复的原理
                   重写equals()和hashCode()方法     先判断hashCode()是否相同,在用equals()进行判断
       3.2).  LinkedHashSet集合
                    LinkedHashSet特点:
                            元素存取有序 (存入和取出顺序一致)      元素不可重复       没有索引
                    LinkedHashSet底层数据结构:
                           哈希表 + 链表   (也就是: 数组 + 链表或红黑树 + 链表)
                          其中, 哈希表用于存储数据, 额外的链表用于记录元素添加时的先后顺序, 以便在获取元素时保持顺序一致
         3.3.)可变参数
                格式: 用在方法的参数中
                        修饰符 返回值类型 方法名(int... 变量名) {
                            // 可以直接将 变量名 当作 数组名 使用
                        }
       3.4).Collections集合工具类
                     java.util.Collections类: 操作集合的工具类
                       Collections.addAll(Collection<? super T> c, T... elements);//往集合中添加一些元素
                       Collections.shuffle(List<E> list);//打乱集合顺序
                       Collections.sort(List<T> list);//将集合中元素按照默认规则排序
                       Collections.sort(List<T> list,Comparator<? super T> c);//将集合中元素按照指定规则排序
              3.4.1). Comparable接口和Comparator接口区别
                     *Collections.sort(List<T> list,Comparator<? super T> c);//将集合中元素按照指定规则排序
                     不能重复:重写hashCode();和equals();方法,查看存入对象重写toString();
                      Comparable: 让JavaBean自身具有可比较性 (自己和其他人比)
                      类继承Comparable<E>       重写compareTo( E   o);方法     return  this.(....) - o.(...);
                      Comparator: 定义一个比较器类, 用比较器对象比 (让第三个人来帮两个人比较)
                      Comparator排序     用匿名对象    new  Comparator<>()   重写 int compare(E o1, E o2) 方法  

                      return    o1.(...) - o2.(..)  =-1   升序
                      return    o2.(...) - o2(..)  =1   降序


04 - Map集合
            java.util.Map<K, V>接口
          4.1.1) Map集合特点:
                     1. 是双列集合, 一个元素包含两个值 (键key, 值value) 键值对
                     2. key和value的类型可以相同, 也可以不同
                     3. key不允许重复, value可以重复
                     4. key和value是一一对应的, 一个键只能对应一个值
           4.1.2)   Map中常用方法
                      java.util.Map接口: 双列集合的顶层
                       Map <E,E>   map = new  HashSet<>();
  map.put(K key, V value);    //添加/修改 键值对. 如果键存在, 新值替换已有值, 如果键不存在, 添加键值对, 返回null
                       map.remove(Object key);    //根据键删除键值对, 返回被删除元素的值   如果键不存在, 返回null
                       map.get(Object key);    //根据键获取值.     如果键不存在, 则返回null
                       map.containsKey(Object key);    // 判断是否包含指定的键
                       Set<K> keySet();    //获取Map集合中所有的键, 存储到Set集合中
                       Set<Map.Entry<K,V>> entrySet();    //获取到Map集合中所有的Entry对象的集合(Set集合)
         4.1.3)Map遍历方式
             (-) keySet()遍历步骤:
                    Map<String, String> map = new HashMap<>();
      
[Java] 纯文本查看 复制代码
       Set<String> keys = map.keySet();
                     for (String key : keys) {
                                  // 通过每个键获取值
                            String value = map.get(key);
                                // 打印当前键值对
                           System.out.println(key + "=" + value);
                   }

                sout("------------------------------------");
            
[Java] 纯文本查看 复制代码
            Iterator<String> iterator = people.iterator();
while (iterator.hasNext()){
String key = iterator.next();
String value = map.get(key);
System.out.println(key+"  "+ value);
}

             (二)Entry键值对对象介绍
                     entrySet()方法遍历Map步骤:
                          Map<String, String> map = new HashMap<>();
                        
[Java] 纯文本查看 复制代码
 Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
  // 通过Entry对象获取每个键值对
String value = entry.getKey();
String value = entry.getValue();
// 打印当前键值对
System.out.println(key + "=" + value);
}

                             sout("------------------------------");
                          
[Java] 纯文本查看 复制代码
   Set<Map.Entry<String, Integer>> entries = map.entrySet();
   Iterator<Map.Entry<String, Integer>> it = entries.iterator();
while (it.hasNext()){
Map.Entry<String, Integer> next = it.next();
  String key = next.getKey();
  Integer value = next.getValue();
System.out.println(key+ "  "+ value);
}

               HashMap存储自定义数据类型作为键
                      HashMap存储自定义JavaBean对象作为key保证key唯一不重复, 需要让JavaBean重写 hashCode() 和 equals() 方法
              LinkedHashMap底层: 哈希表 + 链表
                      key不允许重复, 但key存取有序
         4.2). Hashtable类
                     Hashtable和HashMap:
                        相同点:
                            1. 底层都是哈希表
                        不同点:
                            1. Hashtable不允许存储 null 值和 null 键; HashMap允许存储 null 值和 null 键
                            2. Hashtable线程安全效率低; HashMap线程不安全效率高
                     Hashtable目前很少使用.
                             但其子类 Properties 集合, 可以与IO流结合使用, 应用较多
         4.3).JDK9对集合添加的优化
                      java.util.List接口:
                            // 静态方法
                            static List<E> of(E... e): 返回包含指定元素的 不可变List 集合
                      java.util.Set接口:
                           // 静态方法
                           static Set<E> of(E... e): 返回包含指定元素的 不可变Set 集合
                      java.util.Map接口:
                          // 静态方法
                         static Map<K, V> of(K k1, V v1, ...): 返回包含指定键值对的 不可变Map 集合  
                    注意事项:
                         1. of() 方法只适用于List接口, Set接口, Map接口, 不适用于接口的实现类
                         2. of() 方法的返回值是一个不可变的集合, 集合不能再使用 add(), put() 方法添加元素, 会抛出异常
                         3. Set接口和Map接口在调用 of() 方法的时候, 不能有重复的元素, 否则会抛出异常
          4.4)Debug调试
                       f8:逐行执行程序
                       f7:进入到方法中
                       shift+f8:跳出方法
                        f9:跳到下一个断点,如果没有下一个断点,那么就结束程序
                        ctrl+f2:退出debug模式,停止程序
                        Console:切换到控制
05 - 异常

                 5.1).异常的概念与体系
                              异常:程序执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止
                             java.lang.Throwable  // 体系最顶层
                                     |_ Error         // 不应该试图捕获的严重问题, 不能处理的错误
                                     |_ Exception  // 可以处理的异常

                      5.1.1).异常的分类
                              错误(Error): 不能捕获处理的严重问题. 绝症
                                  必须将程序停下来, 修改代码才能解决
                                  错误的类名都是 "XxxError" 方式
                              异常(Exception): 可以捕获处理的问题. 发烧感冒吃个药就好了
                                     程序执行起来后, 如果有合适的处理方式, 即使发生异常, 程序也能处理该异常并继续运行
                                     异常的类名都是 "XxxException" 方式
                               1. 编译时异常:
                                       编译时期就会发生的异常, 必须在编译时期处理  Unhandled exception XxxException
                               2. 运行时异常:
                                       编译时正常, 运行时才会发生的异常
                  5.2).throw制造异常
                              格式: throw new 异常类名("异常原因字符串");
                              注意:
                                       1. throw 必须写在方法的内部
                                      2. throw 后面new的异常对象, 必须是 "Exception" 或 "Excetion的子类" 的对象
                                      3. 一个方法内部 throw 了一个异常对象, 则该方法可以分为2种情况来处理该异常:
                     如果 throw 的是"运行时异常"(RuntimeException及其子类)对象, 那么可以不处理
                            该异常最终会交给JVM处理, 结果就是: 打印异常信息到控制台, 并立刻结束程序
                     如果 throw 的是"编译时异常"(Exception及其子类), 则必须处理:
                             处理方式1: throws 抛出
                            处理方式2: try...catch 捕获
            5.3).异常处理的方式
                       (一).throws声明抛出异常
                             格式:     //throws 后面的异常类名, 一般是 Exception 或 Exception的子类
                                    修饰符 返回值类型 方法名() throws 异常类名1, 异常类名2, ... {
                                     }

// 示例
  
[Java] 纯文本查看 复制代码

   public static void readFile(String filename) throws FileNotFoundException {
if (!"a.txt".equals(filename)) {  a.java
throw new FileNotFoundException("路径不对");
  }
if (filename.endsWith(".txt")) {  // name.startsWith("张")
       // 判断当前字符串是否以参数的字符串结尾
}
   }

                       (二).捕获异常
                              try...catch:
                                       捕获并处理异常 (方法内部自己处理异常, 不交给别人, "自己背锅")
                               格式:
                                    
[Java] 纯文本查看 复制代码
    try {
  // 可能产生异常的代码
} catch (异常类名 变量名) {
  // 处理异常的代码
// 一般会将异常信息存储到日志中
}
   ...
} catch (异常类名 变量名) {
// 处理异常的代码
// 一般会将异常信息存储到日志中
    }

                                 或者是:
                                       
[Java] 纯文本查看 复制代码
try {
     // 可能发生异常的代码
} catch (异常类型1 | 异常类型2 | 异常类型3 | ... 异常对象名) {
   // 处理任意一个异常的代码
  }

                                 注:
                                           1.如果第一个就是异常,代码就会跳出不会在执行
                                           2. 父类方法声明的异常是什么样的, 子类重写的方法声明异常就什么样, 保持一致即可
                 5.4)Throwable中的3个异常处理方法
                                        String getMessage(): 异常的信息. 没有原因返回null
                                       String toString(): 异常的类型和原因信息
                                       void printStackTrace(): 使用标准错误输出流打印异常信息
                    5.5)finally代码块
                                      格式:
                                             
[Java] 纯文本查看 复制代码
 try {
  // 可能发生异常的代码
   } catch(异常类型 异常变量名) {
                // 处理异常
  }
           ...
  catch(异常类型 异常变量名) {
          // 处理异常
    } finally {
   // 无论是否发生异常, 是否捕获, 最后都会执行的代码.
       // 通常在这里执行释放资源的操作
  }

                                        注:
                                                 1. finally 必须和 try...catch 一起使用
                                                 2. finally 一般用于释放资源 (IO流时用到)
                                                 3.如果 finally 代码块中有 return 语句, 则永远返回 finally 中的 return 语句的值
                                                  应该避免在 finally 中写 return 语句
                     5.6)自定义异常类
                                         如果Java提供的异常类不足以满足我们的需求, 我们也可以自己定义异常类
                                                定义编译时异常: 继承 Exception
                                                定义运行时异常: 继承 RuntimeException

                                                定义2个构造, 一个无参, 一个有String参数

06-多线程
                      6.1)并发与并行
                                      并发: (交替执行) 指两个或多个事件在"同一时间段内"发生
                                       并行: (同时执行) 指两个或多个事件在"同一时刻"发生 (同时发生)
                                  程序启动运行main时候,java虚拟机启动一个进程,主线程main在main()调用时候被创建。
                                  随着调用mt的对象  的start方法,另外一个新的线程也启动了,这样,整个应用就在多线程下运行。
                                  每一个执行线程都有一片自己所属的栈内存空间
                      6.2)创建多线程程序
                       (一).继承Thread类
                               
[Java] 纯文本查看 复制代码
  MyThread extends Thread
//创建线程对象                        
   MyThread  mt = new MyThread();
  mt.start();
                      (=)定义Runnable接口
                              
[Java] 纯文本查看 复制代码
  MyRunnable implements Runnable   
   MyRunnable mr = new MyRunnable();
   //创建线程对象
Thread t = new Thread(mr, "小强");
   t.start();

                                  Thread和Runnable的区别
                                    1. 适合多个相同的程序代码的线程去共享同一个资源。
                                    2. 可以避免java中的单继承的局限性。
                                    3 . 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
                                    4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。
6.3)匿名内部类方式实现线程的创建
//
new Thread()
[Java] 纯文本查看 复制代码
new Thread(){
            @Override
            public void run() {
                  //给线程一个名字
               Thread.currentThread().setName("小明");
                for (int i = 0; i < 10; i++) {
                          //获取线程的名字
                    System.out.println(Thread.currentThread().getName()+"-->"+i);
                }
            }
        }.start();

//普通版Runnable r = new Runnable()

[Java] 纯文本查看 复制代码
Runnable r = new Runnable() {
            @Override
            public void run() {
                Thread.currentThread().setName("小亮");
                for (int i = 10; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName()+"-->"+i);
                }
            }
        };
        new Thread(r).start();


//Runnable简化版
[Java] 纯文本查看 复制代码
new Thread(new Runnable() {
            @Override
            public void run() {
               Thread.currentThread().setName("小红");
                for (int i = 20; i < 30; i++) {
                    System.out.println(Thread.currentThread().getName()+"-->"+i);
                }
            }
        }).start();
    }

07-线程安全
                   7.1).线程同步
                                    (一).同步代码块
                                             Object lock = new Object();
                                                      synchronized(lock){
                                                           需要同步操作的代码
                                                    }

                                   注:
                                       1. 锁对象 可以是任意类型。
                                       2. 多个线程对象  要使用同一把锁。
                                 (二).同步方法
                                        public synchronized void method(){
                                           可能会产生线程安全问题的代码
                                        }

                                     注:
                                         非static 方法 同步锁就是this
                                          static方法,使用当前方法所在类的字节码对象(类名.class)。
                                 (三).Lock锁  
                                          Lock lock = new ReentrantLock();
                                             lock.lock();
                                             
可能会产生线程安全问题的代码
                                               lock.unlock();
08-线程状态
                8.1)六种状态
                                 NEW(新建)    Runnable(可运行)    Blocked(锁阻塞)   
                                 Waiting(无限等待)     Timed Waiting(计时等待) Teminated(被终止)  
                              注:
                                      sleep与锁无关,线程睡眠到期自动苏醒,并返回到Runnable(可运行)状态。
                                       一个调用了某个对象的 Object.wait 方法的线程会等待另一个线程调用此对象的
                                       Object.notify()方法 或 Object.notifyAll()方法。






欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2