java核心编程

java核心编程,第1张

学习总览:


一、集合

1.Collection

1.1 Collection接口
  • 集合: 存储数据的容器(数据结构)

  • Collection:是一个接口,定义了 *** 作集合相关方法

  • Collection下有两个子接口 :List和 Set

1.2 常用方法
​
/**
 * Collection 接口中的方法总结:
 *
 */
public class TestCollection {
​
    public static void main(String[] args) {
        /*
        泛型机制:规定集合中存储的元素类型
         */
        //创建对象,接口类型指向实现类对象——————向上造型
        Collection list1 = new ArrayList();
        /*
        直接打印元素内容的原因是:
            在其继承关系AbstractCollection中重写了toString
         */
        System.out.println(list1);//[]
​
        //常用方法:
        // 1.add(Object o):向集合中添加元素,返回值为boolean
        list1.add("java");
        list1.add("c");
        System.out.println("添加后的集合为:"+list1);
​
        // 2.addAll(Object o):向集合中添加元素,返回值为boolean
        Collection  list2 =   new LinkedList();
        list2.add("c++");
        list2.add("php");
        System.out.println("list2的元素为:"+list2);
        list1.addAll(list2);
        System.out.println("list添加list2的元素后为:"+list1);
​
        //3.contains(Oject o):检测colletion是否包含指定元素,是返回true
            System.out.println("list2集合是否包含c++:"+list2.contains("c++"));  //true
​
        //4.containsAll(Collection list):检测当前colletion是否包含colletion所有元素,是返回true
            System.out.println("list1集合是否包含list2的所有元素:"+list1.containsAll(list2));  //true
​
        //5.equals(Oject o):比较集合是否与指定对象相等,
        Collection  list3 =   new LinkedList();
        Collection  list5 =   new LinkedList();
​
        list3.add("python");
        list5.add("python");
        System.out.println(list3);
        String str = "[python]";
        System.out.println("list3与str是否相等:"+list3.equals(str));  //false
        System.out.println("list3与str是否相等:"+list3.equals("[puthon]"));  //false
        System.out.println("list3与list5是否相等:"+list3.equals(list5));//true
​
        //6.hashCode():返回collection的哈希码
        System.out.println("list3的哈希码为:"+list3.hashCode());
​
        //7.isEmpty():检测colletion不包含元素(空),返回true
        System.out.println(list3.isEmpty());   //false
        Collection  list4 =   new LinkedList();
        System.out.println(list4.isEmpty());   //true
​
        //8.remove(Object o):移除指定元素,存在的话
        list4.addAll(list1);
        System.out.println(list4);   //[java, c, c++, php]
        list4.remove("c");
        System.out.println(list4);   //[java, c++, php]
​
        //9.removeAll(Collection e):移除指定Collection中的所有元素,存在的话
        list4.removeAll(list2);
        System.out.println(list4);  //[java]
​
        //10.retainAll(Collection e):  删除该list4中除了list1的元素
        list4.addAll(list1);
        list4.retainAll(list2);
        System.out.println(list4); // [c++, php]
​
        //11.size()
        System.out.println("list4中的元素个数为:"+list4.size());   //2
​
        //12.toArray()
        Object[] objects = list4.toArray();
        String[]  srings = new String[list4.size()];
        /*
        向下造型,类型转换有问题
        String[]  Strings = (String[]) objects;   无法转型,不符合规范,
          数组有多个元素,多个元素的类型都为Object,
          主要原因:我们需要将存储在Object类型数组中的每一个Object对象都转换为String类型
         */
        for (int i = 0; i < objects.length; i++) {
              String s = (String) objects[i];
              srings[i] = s;
        }
        System.out.println("list4中所有元素的数组:"+Arrays.toString(srings));
​
        System.out.println("list4中所有元素的数组:"+ Arrays.toString(list4.toArray()));
​
        //13.toArray(T[] a):
        String[] strings2 = list4.toArray(new String[list4.size()]);
        System.out.println(Arrays.toString(strings2));
​
        //14.clear():清除所有元素
        list4.clear();
        System.out.println(list4);
    }
}
​

2.List 2.1 List接口
  • List: 有序有重复的集合

  • List常见实现类:

  1. ArrayList: 数组实现 线程非安全效率高

  2. LinkedList: 双向链表 不存在扩容问题

  3. Vector: 数组实现 线程安全,效率低不建议使用

  4. Stack: Vector的子类 数组实现 遵循先进后出的原则

2.2 List使用
  • 测试有序有重复

public static void main(String[] args) {
List lists = new ArrayList();
lists.add(23);
lists.add(15);
lists.add(64);
System.out.println(lists);//23 15 64
/*
有序:指自然顺序 ;存储元素的先后顺序 不是排序
*/
lists.add(64);
//可以有重复元素
System.out.println(lists);
}
 
  • ArrayList的初始容量和扩容机制

        初始容量:10

private static final int DEFAULT_CAPACITY = 10;

        扩容机制: 原来容量的1.5倍

int newCapacity = oldCapacity + (oldCapacity >> 1);
   **ArrayList底层是数组实现,线性结构,更适合查询
2.3 ArrayList和LinkedList区别(重点)

1、数据结构不同
ArrayList是Array(动态数组)的数据结构,LinkedList是Link(链表)的数据结构。
2、效率不同
当随机访问List(get和set *** 作)时,ArrayList比LinkedList的效率更高,因为LinkedList是线性的
数据存储方式,所以需要移动指针从前往后依次查找。
当对数据进行增加和删除的 *** 作(add和remove *** 作)时,LinkedList比ArrayList的效率更高,因为
ArrayList是数组,所以在其中进行增删 *** 作时,会对 *** 作点之后所有数据的下标索引造成影响,需要进行数
据的移动。
3、自由性不同
ArrayList自由性较低,因为它需要手动的设置固定大小的容量,但是它的使用比较方便,只需要创建,然后
添加数据,通过调用下标进行使用;而LinkedList自由性较高,能够动态的随数据量的变化而变化,但是它
不便于使用。
4、主要控件开销不同
ArrayList主要控件开销在于需要在lList列表预留一定空间;而LinkList主要控件开销在于需要存储结点
信息以及结点指针信息。

2.4 截取子串subList

subList(int fromIndex, int toIndex): 索引为前包后不包

/*5.subList(int fromIndex, int toIndex):返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分。
        ---sublist截取子串,和原来的list共用一块资源(SubList是ArrayList的一个内部类,对他 *** 作也是对原list *** 作)
        ---sublist截取的子串如果修改来了,则原list也会改变
        */
        List sublist = list1.subList(2,6);
        for (int i = 0; i < sublist.size(); i++) {
            sublist.set(i,sublist.get(i)*10);
        }
        System.out.println("list1中索引为2-5元素为:"+sublist);
        System.out.println(list1);
2.5  list与数组之间的转换
  • 集合和数组的转化:

  • Object[] toArray()

  • T[] toArray(T[] a)

        //集合转数组
        Object[] objects = list1.toArray();
        System.out.println(objects);

        Integer[] integers = new Integer[list1.size()];
        System.out.println(Arrays.toString(integers));

        //数组转集合
        Integer[] integers1 = new Integer[list1.size()];
        for (int i = 0; i < integers1.length; i++) {
            integers1[i] = (int) (Math.random()*100);
        }
        System.out.println("Interger数组的元素为:"+Arrays.toString(integers));

        List aslist = Arrays.asList(integers1);
        System.out.println("转换后的aslist"+aslist);
        /*
        注意:数组转换后的list不能直接改变,如果改变就会出现UnsupportedOperationException
        asList.add(12);
         */
        /*
        解决方法;可以通过定义一个新的list,然后转换后的aslist添加进去,对新的list *** 作
         */

        ArrayList list3 = new ArrayList<>();
        list3.addAll(aslist);
        System.out.println("新的list添加aslist后:"+list3);
        list3.add(12);
        System.out.println(" *** 作list后:"+list3);
2.6 常用方法

public class TestList1 {
    //作业:测试list接口中定义的其他方法(除了collection中定义的方法及Iterationator相关的方法
    public static void main(String[] args) {
        List list1 = new ArrayList<>();
        list1.add(1);
        list1.add(2);
        list1.add(4);
        list1.add(3);

        //0.add(int index, E element):在列表的指定位置插入指定元素(可选 *** 作)。
        System.out.println("list1为:"+list1);
        list1.add(4,5);
        System.out.println("list1中在索引为4的位置添加元素后为:"+list1);

        //addAll():添加集合,集合长度是+n
        List list2= new ArrayList<>();
        list2.add(12);
        list1.addAll(list2);
        System.out.println("list1中添加list2是:"+list1);


        //1.get(int index):返回列表中指定位置的元素。
        System.out.println("list1中索引为2的元素是:"+list1.get(2));

        //2.indexOf(Object o):返回列表中首次出现指定元素的索引,如果列表不包含此元素,则返回 -1。
        System.out.println("list1中java首先出现的索引为:"+list1.indexOf(4));

        //3.lastIndexOf(Object o):返回列表中最后出现指定元素的索引,如果列表不包含此元素,则返回 -1。
        list1.add(3);
        list1.add(1);
        System.out.println("list1中java最后出现的索引为:"+list1.lastIndexOf(3));

        //4.set(int index, E element):用指定元素替换列表中指定位置的元素(可选 *** 作)。
        System.out.println("list1替换前为:"+list1);
        list1.set(2,6);
        System.out.println("list1替换前后:"+list1);

        /*5.subList(int fromIndex, int toIndex):返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分。
        ---sublist截取子串,和原来的list共用一块资源(SubList是ArrayList的一个内部类,对他 *** 作也是对原list *** 作)
        ---sublist截取的子串如果修改来了,则原list也会改变
        */
        List sublist = list1.subList(2,6);
        for (int i = 0; i < sublist.size(); i++) {
            sublist.set(i,sublist.get(i)*10);
        }
        System.out.println("list1中索引为2-5元素为:"+sublist);
        System.out.println(list1);


        //6.集合转数组
        Object[] objects = list1.toArray();
        System.out.println(objects);

        Integer[] integers = new Integer[list1.size()];
        System.out.println(Arrays.toString(integers));

        //7.数组转集合
        Integer[] integers1 = new Integer[list1.size()];
        for (int i = 0; i < integers1.length; i++) {
            integers1[i] = (int) (Math.random()*100);
        }
        System.out.println("Interger数组的元素为:"+Arrays.toString(integers));

        List aslist = Arrays.asList(integers1);
        System.out.println("转换后的aslist"+aslist);
        /*
        注意:数组转换后的list不能直接改变,如果改变就会出现UnsupportedOperationException
        asList.add(12);
         */
        /*
        解决方法;可以通过定义一个新的list,然后转换后的aslist添加进去,对新的list *** 作
         */

        ArrayList list3 = new ArrayList<>();

        list3.addAll(aslist);
        System.out.println("新的list添加aslist后:"+list3);
        list3.add(12);
        System.out.println(" *** 作list后:"+list3);

    }


}
2.7 总结

/**
 * list:  有序(自然顺序)又重复的集合
 *     有序:自然顺序-->元素添加先后顺序,而不是排序
 *     有重复:可以重复多个相同的元素
 *     4个实现类:
 *          ArrayList:  底层封装了一个Object的数组,非安全线程 ---Object[]  elementData
 *          LinkedList:底层是一个链表(Node)
 *          Vector:底层也是数组,是线程安全,效率慢一点
 *          Stack:底层也是数组,只不过遵循了先进后出的原则
 *
 * ArrayList的扩容机制:
 *      1.当添加第一个元素时,会执行grow方法,给Object[]给一个默认容量 是10
 *      2.当添加后续元素<10时,不会再执行grow方法进行扩容,Object[] 容量为10
 *      3.当添加的元素超出了容量10时,会执行grow方法,Object[] 的容量会进行扩容,扩容机制为1.5倍

 */


3.set
  • Set: 无序无重复的集合

  • Set的常见实现类:

  1. HashSet:底层使用HashMap *** 作数据
  2. TreeSet:底层封装了TreeMap,对元素可以进行排序,树结构 实现 LinkedHashSet:具有自然顺序的 *** 作
3.1  HashSet:

    底层就是HashMap

//创建Set对象。测试HashSet
Set set1 = new HashSet<>();
for (int i = 0; i < 10; i++) {
    set1.add((int)(Math.random()*100));
}
System.out.println(set1);   //无序无重复  
//[97, 98, 5, 38, 72, 89, 25, 58, 63]
3.2  TreeSet:

   底层是TreeMap,排序

//测试TreeSet
Set set2 = new TreeSet<>();
for (int i = 0; i < 10; i++) {
    set2.add((int)(Math.random()*100));
}
System.out.println(set2);   //排序,字符串不能排序
//[20, 22, 29, 42, 60, 62, 64, 72, 74]
3.3  LinkedHashSet:

底层是LinkedHashMap,会按照自然顺序(添加元素的顺序)进行排列

//测试LinkedHashSet:
Set set3 = new LinkedHashSet<>();
set3.add(7);
set3.add(4);
set3.add(1);
set3.add(9);
set3.add(3);
System.out.println(set3);   //自然顺序
//[7, 4, 1, 9, 3]

4.集合排序问题 4.1  Collections
  • Collections是为集合提供的工具类

  • 集合排序的方法为sort(List list),作用是对集合中的元素排序

//包装类数值的排序
//list转换成数组,进行排序
List list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
    list.add((int)(Math.random()*100));
}
System.out.println("排序前:"+list);

Integer[] integers = list.toArray(new Integer[list.size()]);
Arrays.sort(integers);
System.out.println("排序后:"+ Arrays.toString(integers));

Collections.sort(list);   //与上面等价
System.out.println("排序后:"+list);
4.2  对象排序:

                         对属性值将进行排序

  • 使用Collections方法排序的集合元素必须实现Comparable。

  • 如果元素为对象,那么可以通过实现Comparable的compareTo方法为对象添加比较逻辑

  • 案例-根据学生分数进行排序

编写实体类Student:

package com.hqyj.qpi.collections;

public class Student  implements  Comparable{
    private  String name;
    private Integer score;


    public Student(String name, Integer score) {
        this.name = name;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getScore() {
        return score;
    }

    public void setScore(Integer score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", score=" + score +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (name != null ? !name.equals(student.name) : student.name != null) return false;
        return score != null ? score.equals(student.score) : student.score == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + (score != null ? score.hashCode() : 0);
        return result;
    }

    @Override
    public int compareTo(Object o) {
        Student s = (Student) o;//向下造型
        /*
        从小到大,转换为从大到小
          从大到小:this.score - s.getScore()
          从小到大:s.getScore() - this.score

        return  s.getScore() - this.score ;   //从大到小
         */

        return s.getScore() - this.score;   //从小到大

    }
}

                编写测试类:常用顺序

List students = new ArrayList<>();
students.add(new Student("zhangs",90));
students.add(new Student("liu6",70));
students.add(new Student("wang2",89));
students.add(new Student("hus",97));
System.out.println(students.toString());

/*
no instance(s) of type variable(s) T exist so that Student conforms to Comparable
 原因:不知道排序排谁
 解决方法:为Student类提供一套排序规则:Comparable接口为其提供排序规则!
 源码中解释道:
 将此对象(Student)与指定对象(T o)进行排序.返回负整数、零、正整数   小于,等于,大于       */
Collections.sort(students);
System.out.println("排序后的Student:"+students);

                临时改变比较规则

/*
  问题:临时改变比较规则?临时将学生成绩从大到小排序,换成从小到大排列,采用匿名内部类,实现Comparator中的compare方法

 */
Collections.sort(students, new Comparator() {
    @Override
    public int compare(Student o1, Student o2) {
        //从大到小:this.score - s.getScore()
        //从小到大:s.getScore() - this.score
        /*
        o1表示:this
        o2表示:T
         */
        return o1.getScore() - o2.getScore();
    }
});
System.out.println("临时规则比较:"+students);
//临时比较只作用于当前方法,再一次调用时会根据Student中的比较规则

5、Queue 5.1  队列queue
/*
Queue:队列,先进先出
 */
public class TestQueue {

    public static void main(String[] args) {

        Queue queue = new LinkedList<>();
        queue.offer("a");
        queue.offer("b");
        queue.offer("c");
        queue.add("d");
        System.out.println(queue);

        System.out.println("第一次取出的元素:"+queue.poll());  //取出的是最先进去的元素
        System.out.println("第一次取出的元素:"+queue.poll());  //取出的是最先进去的元素
        System.out.println("观察原队列中的元素是否拿出来了:"+queue);   //改变


        //检索但不删除此队列的头部
        System.out.println("检索当前队列头部但不删除"+queue.peek());
        System.out.println("观察原队列中的头元素是否删除了:"+queue);

        //检索并删除此队列的头部
        System.out.println("检索当前队列头部并删除"+queue.remove());
        System.out.println("观察原队列中的头元素是否删除了:"+queue);


    }

}
5.2  双队列Deque
/**
 * Deque:双端队列
 *      --offerFirst 从队首进 pollFirst从队首出
 *      --offerLasst 从队尾进 pollLast从队尾出
 *      --如果限定只从一端进去一端出,则就是栈!s
 */
public class TestDeque {

    public static void main(String[] args) {

        //考虑:继承Queue,offer poll
        Deque deque = new LinkedList<>();
        deque.offerFirst("a");
        deque.offerFirst("b");
        deque.offerFirst("c");
        deque.offerFirst("d");
        deque.offerLast("e");
        deque.offerLast("f");
        deque.offerLast("g");

        //注意:如果我们限制从双端队列的一端进取则和栈的存取原理是一样的
        System.out.println(deque.pollFirst());  //先进后出,同stack(栈)

        System.out.println(deque.pollLast());   //先进先出,队列Queue

    }
}

6、Iterator

/*
Iterable:用于遍历接口
iterator:方法的返回值是iterator对象
 */

List list = new ArrayList<>();
for (int i = 0; i < 10 ; i++) {
    list.add((int)(Math.random()*100));
}
System.out.println(list);
list.add(20);
6.1  迭代器遍历当前集合
System.out.println("----------------通过Iterator遍历------------------");
//1.获取迭代器对象
Iterator iterator = list.iterator();
//2.while循环遍历集合,判断当前集合是否有下一个元素
while (iterator.hasNext()) {
//3.返回需要迭代的对象
    Integer interge = iterator.next();
    System.out.print(interge+"  ");
    if (interge == 20) {
        //list.remove(interge);  不能使用集合提供的remove方法,否则会报错
        iterator.remove();
    }
}
System.out.println();
System.out.println(list);
6.2  增强for循环遍历当前集合
System.out.println("----------------通过for循环遍历------------------");
for (Integer o:list) {
    System.out.print(o + " ");
}
System.out.println();
6.3 forEach遍历集合
 // 1- 通过匿名内部类
System.out.println("----------------通过forEach方法匿名内部类形式遍历------------------");
list.forEach(new Consumer() {
    @Override
    public void accept(Integer integer) {
        System.out.print(integer + " ");
    }
});
System.out.println();


// 2- 通过lambda表达式:重点使用
System.out.println("----------------通过forEach方法lambda形式遍历------------------");
list.forEach(((o)-> System.out.print(o + " ")));

// 3- 通过引用方法形式(流式编程)
System.out.println("----------------通过forEach方法引用方法形式遍历------------------");
list.forEach(System.out::print);

7、Map

             Map集合是以(K-V)键值对的形式存储数据,无序,key可以看为Value的索引,且key是唯一的。

7.1  常见实现类
  • - HashMap:底层使用位桶、链表、红黑树实现(红黑树的加入是jdk1.8后,当链表长度超过阈 值(8)时,使用红黑树),大大减少了查找时间 
  • - TreeMap: 底层位红黑树实现 
  • - LinkedHashMap:按插入的顺序排列。HashMap和双向链表合二为一就是LinkedHashMap 
  • - Hashtable:和HashMap存储原理相似,但方法都是synchronized,因此时线程安全的
7.2  map接口方法实现

7.3  常用方法

import java.util.HashMap;
import java.util.Map;
import java.util.Set;


public class TestMap {
    public static void main(String[] args) {
        //1.创建Map对象
        Map map = new HashMap<>();

        //2.添加元素:put(k,v)
        map.put("chongqing","wanzhou");  //键时唯一的
        map.put("hubei","wuhan");
        System.out.println(map);

        //3.containsKey(Object key):如果此映射包含指定键的映射关系,则返回 true。
        System.out.println("map是否包含hubei这个键:"+map.containsKey("hubei"));

        //4.isEmpty():是否为空!如果此映射未包含键-值映射关系,则返回 true。
        System.out.println("map是否为空:"+map.isEmpty());

        //5.entrySet():返回此映射中包含的映射关系的 set 视图。
        Set> entries = map.entrySet();
        for (Map.Entry o: entries) {
            System.out.println(o);
        }      //遍历
        System.out.println("映射关系的 set 视图"+entries);

        //6.get(Object key):返回此映射中映射到指定键的值。
        System.out.println(map.get("hubei"));

        //7.hashCode():返回此映射的哈希码值。
        System.out.println(map.hashCode());

        //8.keySet():返回此映射中包含的键的 set 视图。
        System.out.println("包含的键的 set 视图:"+map.keySet());

        //9.putAll(Map t):从指定映射中将所有映射关系复制到此映射中(可选 *** 作)。
        Map map2 = new HashMap<>();
        map2.putAll(map);
        System.out.println("map2复制map后为:"+map2);

        //10.remove(Object key) :删除指定键值
        map.remove("hubei");
        System.out.println("检测map是否删除了hubei键值对:"+map);

        //11.size():返回此映射中的键-值映射关系数。
        System.out.println("map2中的键值对数量:"+map2.size());

        //12.values():返回此映射中包含的值的 collection 视图。
        System.out.println(map2.values());

        //13.containsValue(Object value):
        map2.put("china","wanzhou");
        System.out.println("检测wap中是否包含wanzhou对应的键:"+map2.containsValue("wanzhou"));

        //14.clear:移除所有元素
        map.clear();
        System.out.println(map);

    }
}
7.4  底层实现原理

/**
 * Map: k-v key是唯一、无序的
 *
 * HashMap:测试这个类的方法
 * 面试:hashmqp的存储原理  put(k,v)   get(k)
 *       1.HashMap实现:数组加链表   jdk1.8后数组+链表------->数组+链表+红黑树
 *          ---底层封装了一个数组:table
 *          ---在实例化HashMap对象时,没有对数组Node初始化,而是给它设置了一个默认的加载因子0.75f
 */

7.5  hashmap的优化
  • 容量(Capacity): 初始容量为16

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
  • 最大容量

static final int MAXIMUM_CAPACITY = 1 << 30;
  • 元素个数

size()
  • 默认加载因子:size/capacity的结果值, 如果大于0.75,则重新散列(rehashing)

static final float DEFAULT_LOAD_FACTOR = 0.75f;

优化: 加载因子较小时,查找性能会提高,但是会浪费桶容量 0.75是相对平衡状态 因此通过构造方法指定合理的容量,减少重新散列,提高性能。



二、异常处理机制

1.异常处理
  • 异常的父类为Throwable,有两个派生子类Error和Exception

  1. Error:指Java运行环境出现的错误,一般程序不允许出现Error错误,如:JVM的资源耗尽等
  2. Exception:网络故障、文件损坏、用户输入非法等导致的异常,其子类RuntimeException 尤为重要。
  • 异常又可分为检测型异常和非检测型异常

  1. 检测型异常: 编译代码时,程序指出的必须处理的异常,如:InterruptedException、 IOException等。
  2. 非检测异常:运行时才会出现的异常,如:ArrayIndexOutOfBoundsException、 ClassCastException、NullPointerException等。
2.异常处理方式
  • 异常处理的目的:当异常出现,程序就会终止。交给异常处理代码处理(抛出或抓取),其他代码正 常运行

  • 异常处理的方式有两种,抛出或抓取

**   throws :用于方法参数后,对方法中发生异常的代码进行异常抛出

public void testTryCatch() throws InterruptedException {
Thread.sleep(1000);
}

**  try-catch:抓取异常一一处理或直接处理父类异常

public void testTryCatch() {
try {
Thread.sleep(1000);
InputStream is = new FileInputStream("demo.txt");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
或
public void testTryCatch() {
try {
Thread.sleep(1000);//打断性异常
InputStream is = new FileInputStream("demo.txt");//IO异常
} catch (Exception e) {
e.printStackTrace();
}
}

**   finally块:一般跟在catch之后,表示异常处理块的最终出口,无论有没有抛出异常,都会执行 finally中的代码 通常用来进行资源释放等工作

public void testTryCatch() {
try {
Thread.sleep(1000);
InputStream is = new FileInputStream("demo.txt");
} catch (Exception e) {
e.printStackTrace();
System.out.println("异常出现了,QAQ");
} finally {
System.out.println("资源释放...");
}
}

**  throw关键字:用于程序员主动抛出异常

throw new RuntimeException();//抛出新异常
3.常见的方法
  • printStackTrace():打印异常事件发生时的堆栈信息

  • getMessage():打印有关异常事件的信息。

  • getCause():获取异常出现的原因

4.自定义异常

自定义异常:继承Exception

public class MyException  extends  Exception{
​
   public MyException(){
       System.out.println("这是我自己的一个异常");
       System.out.println("this:"+getMessage());
   }
​
    @Override
    public String toString() {
        return "this is a new message";
    }
}
public class TestExceptions {
    public static void main(String[] args) {
​
        try {
            throw  new MyException();
        } catch (MyException e) {
            e.printStackTrace();
        }
    }
}
5、总结 1.异常的处理方式

--第一种:通过throws在方法后抛出,可以抛出多个不同的异常,可以直接抛出父异常Exception --第二种:通过try—catch—finally,可以抓取所有异常并对其进行处理,finally块中不论是否发送异常都会执行 一般用来关闭资源

2.异常常见类型:

--检测型异常(需要处理):编译不通过 --费检测异常:编译通过,运行时异常

3.处理异常时,可以采用throw关键字自行抛出异常 4.异常的常用方法:
  • e.printStackTrace();打印堆栈信息(错误信息)
  • getCause();获取异常原因
  • getMessage();获取异常原因信息
5.自定义异常:

   继承Exception

三、IO流 1、File
  • java.io.File表示文件(目录), *** 作本地的文件和目录。
  • File对象只能 *** 作文件的基本信息(名称、大小等)。不能对文件内容进行访问。
1.1  创建File对象        相对路劲和绝对路劲

                相对路劲:相对于当前书写目录的位置

../demo/a.txt//上级目录的a.txt

                绝对路径:指文件在硬盘上真正存在的路径

D:\IdeaProjects\javase
1.2  File构造方法
  •  File:文件路径或文件对象,不描述文件本身!
  •  文件和目录路径名的抽象表示
import java.io.File;

public class TestFile {

    public static void main(String[] args) {

        //1.构造方法

        //-- File(String  pathname)
        File file = new File("D:\program\A_hqyj\ideaprojects\javase-220302\java-coreprogramming\src\com\hqyj\qpi\io\TestFile.java");
        System.out.println(file);      //  抽象表示
        System.out.println(file.exists());

        //-- File(String parent,String child)
        String parent = "D:\program\A_hqyj\ideaprojects\javase-220302\java-coreprogramming\src\com\hqyj\qpi\io";
        File file2 = new File(parent, "TestFile.java");
        System.out.println(file2.exists());


        //- File(File parent,String child)
        File parentPath = new File(parent);
        File file3 = new File(parentPath, "TestFile.java");
        System.out.println(file3.exists());

        /*
        2.问题来了路径如果传入绝对路径很复杂
           --绝对路径:从盘符开始的路径
           --相对路径:从Module(子工程)开始的   !!!类路径
             -".":系统默认路径
         */
        File file4 = new File("java-coreprogramming\src\com\hqyj\qpi\io\TestFile.java");
        System.out.println(file4.exists());   //相对路径

        //测试相对路径
        File file5 = new File("textFile.txt");
        System.out.println(file5.exists());

        //系统的默认路径
        File file6 = new File(".");
        System.out.println(file6.exists());
        System.out.println(file6.getAbsolutePath());

        /*
            路径分隔符
            -- 正斜杠 /(建议使用)
            -- 反斜杠 \(win独有)
         */

        File file7 = new File("java-coreprogramming/src/com/hqyj/qpi/io/TestFile.java");
        System.out.println(file7.exists());
        


    }

}
1.3  常用方法
import java.io.File;
import java.util.Arrays;
import java.util.Date;

/**
 *
 * 常用方法
 */
public class TestFile2 {

    public static void main(String[] args) throws  Exception {
        //0.准备工作,在io包下创建文件和目录

        
        File file = new File("java-coreprogramming/src/com/hqyj/qpi/io/testfile");
        file.mkdir();
        System.out.println(file.exists());

        //创建一个文件名
        File file2 = new File("java-coreprogramming/src/com/hqyj/qpi/io/testfile/demo.properties");
        file2.createNewFile();

        //测试此文件是否可读
        System.out.println(file2.canRead());

        //4.测试是不是一个文件或者目录
        System.out.println(file2.isFile());
        System.out.println(file2.isDirectory());

        //5.返回路径或者文件最后一次被修改的时间
        System.out.println(new Date(file2.lastModified()));

        //6.获取此抽象文件或者目录的名称
        System.out.println(file2.getName());

        //7.判断当前文件是否可写
        System.out.println(file2.canWrite());

        //8.获取文件的长度
        System.out.println(file2.length());

        //9.创建多级目录
        File file3 = new File(file, "a");
        System.out.println(file3.mkdirs());

        //10.删除一个路径
        file3.delete();

        //问题:File对象 *** 作的是文件内容还是文件的基本信息呢?  *** 作的是文件的基本信息
           //File 就是该文件路径表示的对象,而不是 *** 作内容本身。

        //11.打印当前目录下的所有内容
        File file4 = new File(".");
        File[] files = file4.listFiles();
        System.out.println(Arrays.toString(files));

        String[] list = file4.list();
        System.out.println(Arrays.toString(list));



    }
}

2、IO流概述
  • IO:指输入输出

       Input:输入,从外界到程序,读取数据

       Output:输出,从程序到外界,写出数据

  • 流的分类:

        **字节流和字符流

                字节流: 传输数据的最小单位是字节         

                字符流: 传输数据的最小单位是字符

        **节点流(低级流)和处理流(高级流或过滤流)

                节点流: 可以向一个特定的地方读写数据

                处理流: 封装了节点流,通过封装的流的功能调用实现数据读写。

         **流的链接: 一个流对象经过其他流的多次包装,成为流的链接。


3、字节流
  • 字节流有两个抽象类: InputStream和OutputStream
  • IS(InputStream)的常用方法
  • OS(OutputStream)的常用方法
3.1 FIS和FOS

         3.1.1 字节流FIS和FOS

  •                FIS: FileInputStream,文件输入流

FileInputStream(File file)

        通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中 的 File 对象 file 指定。

FileInputStream(String name)

        通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中 的路径名 name 指定。

  •                FOS:FileOutputStream, 文件输出流

FileOutputStream(File file)

        创建一个向指定 File 对象表示的文件中写入数据的文件输出流。

FileOutputStream(File file, boolean append)

        创建一个向指定 File 对象表示的文件中写入数据的文件输出流。

FileOutputStream(String name)

        创建一个向具有指定名称的文件中写入数据的输出文件流。

FileOutputStream(String name, boolean append)

        创建一个向具有指定 name 的文件中写入数据的输出文件流。

        3.1.2  FileInputStream的读出与写入

/**
 * fileInputStream FileOutputSream
 *
 *
 * 字节流:凡是以Stream结尾的都是字节流
 */
public class TestFISAndFOS2 {

    public static void main(String[] args) throws  Exception{

        //读入
        InputStream inputStream = null;
        OutputStream outputStream = null;

        File file = new File("java-coreprogramming/src/com/hqyj/qpi/io/testfile/fis1.txt");
        try {
            inputStream= new FileInputStream(file);

            for (int j= 1; ; j++) {
                 int io = inputStream.read();
                if (io == -1) {
                    break;
                }
                System.out.print((char ) io);
            }
        }catch (Exception e){
            e.printStackTrace();
        } finally {
            inputStream.close();
        }
        System.out.println();


        //写出
        byte[] bytes = new byte[]{'o','u','t'};
        try {
            outputStream = new FileOutputStream(file,true);
            outputStream.write(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            outputStream.close();
        }

    }
}

    3.1.3 文件内容的复制

      此刻需要用到单元测试,以下为单元测试内容

      1.测试读写

                --单元(每一个方法都是一个单元)测试:

                         --@Before :同一个java中,执行@Test前必须执行的内容

                         --@After :同一个java中,执行完@Test后必须执行的内容

                         --@Test :同一个java中,必须执行@Test的内容 

      2.单元测试路径

                 绝对路径:从盘符开始

                 相对路径:单元测试编译位置和main函数不同

                         --main从module开始

                         --单元测试从Classpath开始(类路径)

                         -- 可以标记一个普通的文件目录为classpath Make Directory As 

测试:

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.*;

/*
        测试读写
          --单元(每一个方法都是一个单元)测试:
             --@Before :同一个java中,执行@Test前必须执行的内容
             --@After :同一个java中,执行完@Test后必须执行的内容
             --@Test :同一个java中,必须执行@Test的内容
         */
public class TestFISAndFOS3  {

    //练习通过上面的案例尝试读取文件中所有的字节,并尝试创建OutputStream,向文件中写入内容

    File file;
    FileInputStream fis;
    FileOutputStream fos;

    //准备资源
    @Before
    public void testBefore(){
        /*
        单元测试:
            绝对路径:从盘符开始
            相对路径:单元测试编译位置和main函数不同
                    --main从module开始
                    --单元测试从Classpath开始(类路径)
                      可以标记一个普通的文件目录为classpath
                      Make Directory As
         */
        String path  = "resource\fis1.txt";
        file = new File(path);
    }

    //写
    @Test
    public void testWirte() throws  Exception{
        /*
        构造方法中:boolean append参数如果为true表示追加
         */
        fos = new FileOutputStream(file,true);
        fos.write(65);


    }

    //读
    @Test
    public  void  testRead() throws  Exception{

        fis = new FileInputStream(file);
        int i = -1;
        while ((i = fis.read()) != -1) {
            System.out.println((char)i);
        }

    }

    //byte[]写
    @Test
    public void  testWriteByts() throws  Exception{
        fos = new FileOutputStream(file,true);
        byte[] bytes1 = new byte[]{65,66,67,68,69};
        fos.write(bytes1);
    }

    //byte[]读
    @Test
    public void  testReadByts() throws  Exception{
        fis = new FileInputStream(file);
        byte[] bytes2 = new byte[100];
        int i = fis.read(bytes2);
        System.out.println(new String(bytes2));
    }

    //测试使用fis和fos实现文件的复制 将fis1.txt的内容复制到fis1_copy.txt,采用byte实现
    //byte复制
    @Test
    public void  testcopy() throws  Exception {
        //定义文件路径
        fis = new FileInputStream(file);
                            //如果没有文件,会自动生成文件
        fos = new FileOutputStream("resource\fis1_copy.txt");
        //定义数组
        byte[] bytes = new byte[1024];
        //读
        fis.read(bytes);

        //写
        fos.write(bytes);

             /*
        int i = -1;
        while(i = fis.read(bytes) != -1) {
            fos.write(bytes);
        }
         */
    }

    //关闭资源
    @After
    public void testAfter() throws  Exception{
        if (fos != null){
            fos.close();
        }
        if (fis != null) {
            fis.close();
        }
    }

}
3.2 BIS和BOS
  • 缓冲区的优势:减少了读写次数
  • flush() : 清空缓冲区,将缓冲区中的数据全部写出
  • BIS:BufferedInputStream 缓冲输入流

BufferedInputStream(InputStream in)

                创建 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。 BufferedInputStream(InputStream in, int size)

                创建具有指定缓冲区大小的 BufferedInputStream,并保存其参数,即输入流 in,以 便将来使用。

  • BOS:BufferedOutputStream 缓冲输出流

BufferedOutputStream(OutputStream out)

                创建一个新的缓冲输出流,以将数据写入指定的基础输出流。 BufferedOutputStream(OutputStream out, int size)

                创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的基础输出流。

3.2.1  缓冲输入输出流

public class TestBISAndBOS {

    File file;
    FileInputStream fis;
    FileOutputStream fos;
    BufferedInputStream bis;
    BufferedOutputStream bos;

    @Before
    public  void  createFile() throws Exception {
        String s = "resource\bis1.txt";
        file = new File(s);

    }

    //写出
    @Test
    public  void write() throws  Exception {
        //先去创建低级流
        fos = new FileOutputStream(file);
        bos = new BufferedOutputStream(fos,10); //以低级流fos作为载体
        //写出内容
        bos.write("I am a boy".getBytes());
        bos.flush();//立即写出
    }

    //读入
    @Test
    public  void read() throws  Exception {
        fis = new FileInputStream(file);
        bis = new BufferedInputStream(fis);
        byte[] bytes = new byte[1024];
        //读入
        bis.read(bytes);
        System.out.println(new String(bytes));
    }
   

    @After
    public  void  close() throws  Exception {
        //先关闭高级流,在关闭低级流
        if (bos != null)
            bos.close();
        if (bis != null)
            bis.close();
        if (fos != null)
            fos.close();
        if (fis != null)
            fis.close();
    }

}

3.2.2复制文件的内容

public class TestBISAndBOS {

    File file;
    FileInputStream fis;
    FileOutputStream fos;
    BufferedInputStream bis;
    BufferedOutputStream bos;

    @Before
    public  void  createFile() throws Exception {
        String s = "resource\bis1.txt";
        file = new File(s);

    }

    //写出
    @Test
    public  void write() throws  Exception {
        //先去创建低级流
        fos = new FileOutputStream(file);
        bos = new BufferedOutputStream(fos,10); //以低级流fos作为载体
        //写出内容
        bos.write("I am a boy".getBytes());
        bos.flush();//立即写出
    }

    //读入
    @Test
    public  void read() throws  Exception {
        fis = new FileInputStream(file);
        bis = new BufferedInputStream(fis);
        byte[] bytes = new byte[1024];
        //读入
        bis.read(bytes);
        System.out.println(new String(bytes));
    }
    //复制文件内容
    //练习:使用bis和bos实现文件的复制,bis_copy.txt,参考fis和fos的方法
    @Test
    public void testcopy() throws Exception {
        fis = new FileInputStream(file);
        bis = new BufferedInputStream(fis);
        fos = new FileOutputStream("resource\bis_copy.txt");
        bos = new BufferedOutputStream(fos);
        byte[] b = new byte[1024];
        int i = -1;
        while (( i = bis.read(b)) != -1) {
            bos.write(b);
        }
    }

    @After
    public  void  close() throws  Exception {
        //先关闭高级流,在关闭低级流
        if (bos != null)
            bos.close();
        if (bis != null)
            bis.close();
        if (fos != null)
            fos.close();
        if (fis != null)
            fis.close();
    }

}

4、对象流 4.1 序列化和反序列化
  • 序列化:对象转化为字节序列
  • 反序列换:字节序列转化为对象
4.2 OIS和OOS
  • OIS:ObjectInputStream,对象输入流

ObjectInputStream(InputStream in)

                                  创建从指定 InputStream 读取的 ObjectInputStream。

  • OOS:ObjectOutputStream,对象输出流

ObjectOutputStream(OutputStream out)

                                 创建写入指定 OutputStream 的 ObjectOutputStream。

4.3常用方法

                序列化

void writeObject(Object o);

                反序列化

Object readObject();

  • 对象序列化的注意事项:
  1. 必须实现Serializable接口,该接口没有方法
  2. 建议为对象添加类版本号,避免版本升级后造成的不兼容问题
  3. transient关键字:修饰属性可以对没必要的属性值忽略,从而对对象序列化后的字节序列”瘦 身“
4.4实现

                实体类:


import java.io.Serializable;

public class Person implements Serializable {

    private static final long serialVersionUID = -516804566657580250L;
    private String name;
    private transient int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Person person = (Person) o;

        if (age != person.age) return false;
        return name != null ? name.equals(person.name) : person.name == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }
}

                测试:



import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.*;

public class TestOisAndOos {
    /*
    1.怎么对实体类进行序列化和反序列化
    2.创建ois和oos

     */
    File file;
    FileOutputStream fos;
    FileInputStream fis;
    BufferedOutputStream bos;
    BufferedInputStream bis;
    ObjectInputStream ois;
    ObjectOutputStream oos;

    @Before
    public  void  filepath() throws Exception {
        String str = "resource//ois.txt";
        file = new File(str);

    }
    @Test   //序列化
    public  void testWrite() throws  Exception {
        fos = new  FileOutputStream(file);
        oos = new ObjectOutputStream(fos);
        Person person = new Person("zhagns", 16);
        oos.writeObject(person);
    }


    @Test   //反序列化
    public void testRead() throws  Exception {
        fis = new FileInputStream(file);
        bis = new BufferedInputStream(fis);
        ois = new ObjectInputStream(bis);
        Object o = ois.readObject();
        System.out.println(o);
    }

    @After
    public void close() throws  Exception {
        if (ois != null) ois.close();
        if (oos != null) oos.close();
        if (bis != null) bis.close();
        if (bos != null) bos.close();
        if (fis != null) fis.close();
        if (fos != null) fos.close();

    }
}

序列化多个对象:



import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.*;

public class TestOisAndOos2 {
    /*
    序列化多个对象:

     */
    File file;
    FileOutputStream fos;
    FileInputStream fis;
    BufferedOutputStream bos;
    BufferedInputStream bis;
    ObjectInputStream ois;
    ObjectOutputStream oos;

    @Before
    public  void  filepath() throws Exception {
        String str = "resource//ois.txt";
        file = new File(str);

    }
    @Test   //序列化
    public  void testWrite() throws  Exception {
        fos = new  FileOutputStream(file);
        oos = new ObjectOutputStream(fos);

        Person[] persons = new Person[2];
        persons[0] = new Person("li4",25);
        persons[1] = new Person("li5",32);
        for (int i = 0; i < persons.length; i++) {
            oos.writeObject(persons[i]);
        }


    }


    @Test   //反序列化
    public void testRead() throws  Exception {
        fis = new FileInputStream(file);
        bis = new BufferedInputStream(fis);
        ois = new ObjectInputStream(bis);

         Object[] objects = new Object[2];
        for (int i = 0; i < objects.length; i++) {
            Object o = ois.readObject();
            System.out.println(o);
        }

    }

    @After
    public void close() throws  Exception {
        if (ois != null) ois.close();
        if (oos != null) oos.close();
        if (bis != null) bis.close();
        if (bos != null) bos.close();
        if (fis != null) fis.close();
        if (fos != null) fos.close();

    }
}

总结:

1.对象序列化时,序列化对象类型必须实现Serializable,否则会报错
2.对象的实现序列化和返序列化
    - 序列化:OOS的writeObject方法
    - 反序列化:OIS的readObject方法
3.transient关键字:在序列化时,不考虑该关键字
      Person person = new Person("zhagns", 0);
      private transient int age;
      序列化和反序列化都不考虑age属性
4.serialVersionUID(序列化号)
    -功能:解决不兼容   序列化一个对象到内存中,反序列化时值发生变化
    当没有UID时,会直接报错
    有UID时会返回空
5.多个对象的序列化过程,可以采用数组/集合的形式去完成

5、字符流
  • 字符流有两个抽象类 Reader和Writer
  • 字符流的底层是字节流,每次处理一个字符(char)
  • 常见字符集:
  1. UTF-8:是针对Unicode的一种可变长度字符编码。
  2. GBK:汉字编码字符集。
  • Reader常用方法 Writer常用方法
5.1 ISR和OSW
  • ISR:InputStreamReader,字符输入流

InputStreamReader(InputStream in)

                创建一个使用默认字符集的 InputStreamReader。 InputStreamReader(InputStream in, String charsetName)

                创建使用指定字符集的 InputStreamReader。

  • OSW:OutputStreamWriter,字符输出流

OutputStreamWriter(OutputStream out)

                创建使用默认字符编码的 OutputStreamWriter。 OutputStreamWriter(OutputStream out, String charsetName)

                创建使用指定字符集的 OutputStreamWriter。

测试:


import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.*;

/**
 * 字符流,指的是按照字符
 *   以Reader和Writer结尾的
 */
public class TestRSRAndOSW {

    /*
    通过ISR和OSW实现文件的复制
         */

    File file;
    FileInputStream fis;
    FileOutputStream fos;
    InputStreamReader isr;
    OutputStreamWriter osw;

    @Before
    public void bigin() throws  Exception {
        file = new File("resource//isr.txt");
    }
    @Test
    public void write() throws  Exception {
        fos = new FileOutputStream(file);
        osw = new OutputStreamWriter(fos);
        osw.write("I love java");

    }
    @Test
    public void read() throws Exception {
        fis = new FileInputStream(file);
        isr = new InputStreamReader(fis);
        char[] chars = new char[100];
        isr.read(chars);
        System.out.println(chars);
    }
    @Test
    public void copyFile() throws Exception {
        fis = new FileInputStream(file);
        isr = new InputStreamReader(fis);
        fos = new FileOutputStream("resource//isr_copy.txt");
        osw = new OutputStreamWriter(fos);

        char[] chars = new char[100];
        int i = -1;
        while ((i = isr.read(chars) ) != -1) {
            osw.write(chars);
        }
    }
    @After
    public void close() throws  Exception {
        if (isr != null) isr.close();
        if (osw != null) osw.close();
    }
}
5.2 PW和BR
  • PW:PrintWriter,输出打印流

--构造方法

PrintWriter(File file)

        使用指定文件创建不具有自动行刷新的新 PrintWriter。

PrintWriter(File file, String csn)

        创建具有指定文件和字符集且不带自动刷行新的新 PrintWriter。 PrintWriter(OutputStream out)

        根据现有的 OutputStream 创建不带自动行刷新的新 PrintWriter。 PrintWriter(OutputStream out, boolean autoFlush)

        通过现有的 OutputStream 创建新的 PrintWriter。

PrintWriter(String fileName)

        创建具有指定文件名称且不带自动行刷新的新 PrintWriter。

PrintWriter(String fileName, String csn)

        创建具有指定文件名称和字符集且不带自动行刷新的新 PrintWriter。

PrintWriter(Writer out)

        创建不带自动行刷新的新 PrintWriter。

PrintWriter(Writer out, boolean autoFlush)

        创建新 PrintWriter。

--常用方法

        PW提供了丰富的print方法和println方法的重载方法

                自动行刷新: 从本地读取一个文件,再写回去

 String path = "src\com\hqyj\qpi\io\pwandbr\pw.txt";

    @Test
    public  void write() throws  Exception  {

        PrintWriter pw = new PrintWriter(new BufferedOutputStream(new FileOutputStream(path)), true);
        pw.write("大家好!");
        pw.write("23");
        pw.print("456");
        pw.println("789");
        pw.close();

    }
  • BR:BufferedReader:缓冲字符输入流

-- 构造方法

BufferedReader(Reader in)

        创建一个使用默认大小输入缓冲区的缓冲字符输入流。

BufferedReader(Reader in, int sz)

        创建一个使用指定大小输入缓冲区的缓冲字符输入流。

-- 常用方法 String readLine()

        连续读取一行字符串,直到读取到换行符为止,返回的字符串中不包含该换行符

                测试:

String path = "src\com\hqyj\qpi\io\pwandbr\pw.txt";
@Test
    public void read() throws  Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(path)));
//        char[] chars = new char[1024];
//        int i = -1;
//        while ((i = br.read(chars)) != -1) {
//            System.out.println(new String(chars));
//        }
        String s = br.readLine();   //读取行
        System.out.println(s);
        br.close();   //必须关闭最上层的流


    }
6、练习

6.1输入一个字符串,统计出现的字符个数,并写入文件中,文件名为count.txt


import java.io.*;
import java.util.Scanner;
import java.util.TreeMap;



public class homeWork {

    //测试
    public static void main(String[] args) throws  Exception {

        //a.提示信息
        System.out.println("请输入一个字符串:");
        //b.输入字符串
        Scanner scanner = new Scanner(System.in);
        String str = scanner.nextLine();

        //c.统计个数
        homeWork hw = new homeWork();
        String s = hw.wordCount(str);

        //d.存储在文件中
        String path = "D:\\program\\A_hqyj\\ideaprojects\\javase-220302\\java-coreprogramming\\resource\\count.txt";
        hw.intoFile(path,s);
        System.out.println("结果已生成,查看count.txt");

    }

    //统计字符个数
    public String wordCount(String inputStr) {
        //a.对字符串进行处理
        char[] chars = inputStr.toCharArray();
        //b.选择数据结构
        TreeMap maps = new TreeMap<>();

        //c.遍历
        for (int i = 0; i < chars.length; i++) {
            //d.将数据存储进map中
            maps.put(chars[i],maps.containsKey(chars[i])?maps.get(chars[i]) + 1 : 1);
        }
        return  maps.toString();
    }
    //将结果写进结果中
    public void intoFile(String path,String s) throws  Exception{
        OutputStreamWriter osw = new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(new File(path))));
        osw.write(s);   //写入到缓冲区了,没有写入文件——————>1.flush  2.关闭流
        if (osw != null)
            osw.close();


    }


}


四、多线程 1.线程和进程 1.1进程和线程概述

        进程(Process):是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和 调度的基本单位,是 *** 作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基 本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组 织形式的描述,进程是程序的实体。

        线程:线程(英语:thread)是 *** 作系统能够进行运算调度的最小单位。它被包含在进程之中,是 进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个 线程,每条线程并行执行不同的任务。

1.2 并发和并行

        并发:指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多 个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速 交替的执行。

        并行:真正意义的同时发生


2.线程的生命周期

 线程的5种状态

  起始:当使用new关键字创建线程对象时

  就绪:调用start方法启动线程时,指能运行但还没有运行的过程,会等待CPU为其分配时间 片。

  运行:执行run方法时

  阻塞:当线程中断、主动出让、等待、睡眠时,会重新进入就绪状态

  结束:指run方法执行完毕时


3.线程创建 3.1继承Thread类

      通过继承Thread类重写run()方法实现


/**
 * 创建方式:继承Thread类
 */
public class TestThread1 extends  Thread{

    //重写父类的run方法,编写自己定义的线程的执行体
    @Override
    public void run() {    //3.run 运行状态
        System.out.println("t1");
        //打印当前线程的名称
        for (int i = 0; i < 100; i++) {
            System.out.println(this.getName()+"->"+i);
        }
        /*
         try {
            sleep(2);   //4.阻塞状态
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
         */

    }   //5.结束状态

    public static void main(String[] args) {
        TestThread1 t1 = new TestThread1();  //1.new 起始状态
        t1.start();   //2.start  就绪状态(没有运行,等待CPU的时间片)

        System.out.println(Thread.currentThread().getName());

        //1.测试创建多条线程
        new TestThread1().start();
        new TestThread1().start();
        new TestThread1().start();

    }
}
3.2实现Runnable接口

        通过实现Runnable接口重写run()方法

        分为三种方式: 

                1.常规的Runnable接口

                2.匿名内部类

                3.lambda表达式



/**
 * runnable接口实现
 */
public class TestThread3 implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " t");
    }

    public static void main(String[] args) {
        //实现Runnable接口,线程创建的三种方法

        //1.常规写法,构造方法中一般传入实现Runnable接口的实现类
        Thread t = new Thread(new TestThread3());
        t.start();

        //2.匿名内部类形式
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " t1");

            }
        }).start();


        //3.lambda表达式 -----前提:必须为接口,接口中只能有一个方法
        new Thread(() -> System.out.println(Thread.currentThread().getName() + " t3")).start();
    }
}
3.3继承Callable接口

       实现Callable接口,可以定义返回指定的泛型,依赖FutuerTask类

       同样也是有三种方式:

                1.常规的Callable接口

                2.匿名内部类

                3.lambda表达式



import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

/**
 * 问题:实现Callable接口,泛型
 *      --能在方法中返回一个返回值,且这个返回值存储在FutureTask
 */
public class TestThread4 implements Callable {

    @Override   //等价于run方法
    public Integer call() throws Exception {
        Integer sum = 0;
        for (int i = 0; i <= 100; i++) {
            sum += i;
        }
        System.out.println(Thread.currentThread().getName());
        return sum;
    }

    public static void main(String[] args) throws  Exception{
        FutureTask task = new FutureTask(new TestThread4());
        new Thread(task).start();  //绑定
        System.out.println(task.get());

        //2.匿名内部类
        new Thread(new FutureTask(new Callable() {
            @Override
            public Integer call() throws Exception {
                Integer sum = 0;
                for (int i = 0; i <= 100; i++) {
                    sum += i;
                }
                System.out.println(Thread.currentThread().getName());
                return sum;
            }
        })).start();

        //3.lambda表达式
        FutureTask task1 = new FutureTask<>(() -> {

            Integer sum = 0;
            for (int i = 0; i <= 100; i++) {
                sum += i;
            }
            System.out.println(Thread.currentThread().getName());
            return sum;

        });
        new Thread(task1).start();
        System.out.println(task1.get());
    }


}

3.4线程池的创建

        工厂类Executors

常用方法:

static ExecutorService newCachedThreadPool()

        创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它 们。 static ExecutorService newFixedThreadPool(int nThreads)

        创建一个可重用固定线程集合的线程池,以共享的无界队列方式来运行这些线程。

static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

        创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。

static ExecutorService newSingleThreadExecutor()

        创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。



import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

/**
 * 创建方式4:线程池   Executors:工具类,提供了很多的线程
 *
 */
public class TestThread5  {

    public static void main(String[] args) {

        //创建一个线程池,有3个线程
        ExecutorService pool = Executors.newFixedThreadPool(3);


        for (int i = 0; i < 100; i++) {
            pool.execute( () -> System.out.println(Thread.currentThread().getName()) );
            //excute:相当于start
        }
        pool.shutdown();   //关闭线程池

        //Callable和Runable有什么关联
           /*
           线程池可以把Runnable交给Callable去执行
            */

    }

}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/739761.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-28
下一篇 2022-04-28

发表评论

登录后才能评论

评论列表(0条)

保存