黑马程序员技术交流社区

标题: [石家庄校区]JAVA_线程_Lambda表达式_File类_IO流 [打印本页]

作者: 13333114253    时间: 2018-11-26 14:39
标题: [石家庄校区]JAVA_线程_Lambda表达式_File类_IO流
本帖最后由 13333114253 于 2018-12-3 09:31 编辑

01-线程间通讯
     等待唤醒机制介绍:
           等待唤醒机制:  一个线程进行了规定操作后,就进入等待状态( wait() ),等待其他线程执行完他们的制定代码过后再将其唤醒 (  notify()  );
           再有多个线程进行等待时,如果需要可以使用  notifyAll() 来唤醒所有的等待线程
     等待唤醒中的方法:
           成员方法只能通过"锁对象"调用
           void  notify() ;//随机唤醒在同一个锁对象上的某一处等待状态的线程
          void  notifyAll();   //唤醒同一锁上处于等待的线程
          void wait();    //线程处于无线等待状态,同时释放锁资源
调用wait()和notify() 需要注意的细节:
       1.wait()和notify()必须通过由"同一个锁对象"调用
       2.wait()和notify()属于Object类的方法      锁对象可以是任意对象,都继承于Object类
       3.wait()和notify()必须要在"同步带码块"或者是"同步方法"中使用
02-线程池
线程池:
          一个容纳多个线程的容器         其中的线程可以反复使用,省去频繁创建线程对象的操作,无需反复创建线程而浪费资源
线程池代码的实现
         java.util.concurrent.Executors类: 线程池工厂类, 用于管理线程池
        // 静态方法:
        static ExecutorService newFixedThreadPool(int nThreads): 创建固定数量线程的线程池(常用)     
                                    一哥载Q特儿 色儿微斯
        java.util.concurrent.ExecutorService接口: 真正执行任务的线程池服务
        // 成员方法:
        Future submit(Runnable task): 提交一个Runnable任务
        void shutdown(): 通知线程执行完任务后关闭. 如不调此方法, 则线程执行完任务后仍在运行以便重复使用
     
线程池的创建和使用步骤:
        1. 使用Executors的静态方法 newFixedThreadPool(int nThreads) 创建线程池ExecutorService
        2. 创建一个任务类, 实现Runnable接口, 重写run()方法
        3. 调用ExecutorService对象的 submit(Runnable task) 方法, 传递任务给线程池, 执行任务
        4. 调用ExecutorService对象的 shutdown() 方法, 销毁线程池 (不建议执行)

例:
模拟饭店服务员
饭店有2个服务员, 有2个桌子, 来了10个顾客, 同一时间只能有2个顾客入座用餐, 其余顾客要等待

[Java] 纯文本查看 复制代码
public class RunnableImpl implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"服务员开始为顾客点菜");
        System.out.println("顾客"+this.hashCode()+"开始用餐");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("顾客"+this.hashCode()+"用餐完毕");
        System.out.println(Thread.currentThread().getName()+"服务员收拾桌子");
        System.out.println("-------------------------------");
    }
}

public class Test {
    public static void main(String[] args) {
        // 创建线程池, 有2个线程, 模拟2个桌子
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        // 循环10次模拟10个顾客来用餐
        for (int i = 0; i < 10; i++) {
            executorService.submit(new RunnableImpl());
        }
        // 都执行完后关闭线程池
        executorService.shutdown();
    }
}

03-函数式编程思想:Lambda表达式函数式编程思想
函数式:
               强调做事(不关心用什么对象,重写什么方法)
面向对象与函数表达式的对比
[Java] 纯文本查看 复制代码
// 面向对象方式的代码
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "新线程创建了");
        }
    }).start();


    // 函数式编程的代码
    new Thread(()-> {
            System.out.println(Thread.currentThread().getName() + "新线程创建了");
        }
    ).start();

Lambda标准格式
Lambda标准格式 表达式的3个部分
1.一些参数()
       接口中抽象方法的参数列表,没参数就空着;有参数就写用逗号隔开
2.一个箭头->
      将参数传递给方法体
3.一段代码 {}
     重写接口抽象方法的方法体
格式:
(参数列表)->{重写方法的方法体}
Lambda省略格式和使用前提
省略原则:
        可推导的都可省略 (凡是能根据前后代码能猜测出来的代码, 都可以省略不写)
    可以省略的部分:
       1. (参数列表): 参数"类型"可以省略
        2. (参数列表): 如果参数只有1个, 则"类型"和"小括号"都可以省略  a -> sout(a)
        3. {一些代码}: 如果只有一条代码, 则"大括号", "return", "分号"都可以"一起省略"

*函数式接口:
        函数式接口"有且仅有一个抽象方法"
        但函数式接口对于哪些方法算作抽象方法有特殊规定:
                1. 有方法体的方法"不算作"抽象方法, 如默认方法, 静态方法, 私有方法
                2. 抽象方法与java.lang.Object类中的方法定义相同的, 也"不算作"抽象方法3
                        因为任何实现本接口的实现类, 都会直接或间接继承java.lang.Object类的public的方法, 所以在创建实现类时其实不用重写该抽象方法, 也就不算作抽象方法

Lambda表达式的使用前提:
    1. Lambda只能用于接口, 且"接口中有且仅有一个抽象方法"(也称为"函数式接口")
        普通类, 抽象类不能用
    2. 使用Lambda必须具有上下文推断
        方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例
        (简而言之: 作为参数类型的接口, 必须是函数式接口)

04-File类
绝对路径和相对路径
绝对路径:
        以盘符开始的路径
        如: "D:\\a\\hi.txt"
相对路径:
        不以盘符开始的简化路径. 相对于项目的根目录
        如: "a\\1.mp3", "123.txt"


File类: 构造方法
java.io.File类: 文件和目录的路径名的抽象表现形式, 主要用于文件和目录的创建, 查找和删除等操作
        // 构造方法(创建了File对象, 并将其指向该路径. 不会真正在磁盘上创建这个文件)
        File File(String pathname): 根据 路径字符串 封装一个File对象
        File File(String parent, String child): 根据 父路径字符串 和 子路径字符串 封装File对象
        File File(File parent, String child): 根据 父路径的File对象 和 子路径 封装File对象

测试构造方法:
[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        // File File(String pathname): 根据 路径字符串 封装一个File对象
        File f1 = new File("z:\\z.txt");  // 不存在的路径也可以创建File对象
        System.out.println(f1);

        // File File(String parent, String child): 根据 父路径字符串 和 子路径字符串 封装File对象
        File f2 = new File("a\\", "a.txt");  // 相对路径也可以
        System.out.println(f2);

        // File File(File parent, String child): 根据 父路径的File对象 和 子路径 封装File对象
        File f3 = new File(new File("d:\\"), "d.txt");
        System.out.println(f3);

        // 创建File对象后, 并不会在磁盘上创建文件或目录!
    }
}


File类: 获取方法
java.io.File类
    // 常用获取方法
    String getAbsolutePath(): 返回此File的绝对路径名字符串
    String getPath(): 获取File对象的封装路径 (创建对象时传入的路径)
    String getName(): 获取File对象的文件名或目录名
    long length(): 获取File表示的文件大小的字节数 (不能获取目录的大小)

[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        // String getAbsolutePath(): 返回此File的绝对路径名字符串
        File f1 = new File("a.txt");
        System.out.println(f1.getAbsolutePath());  // File对象是相对路径, 该方法可以获取到绝对路径
         
        // String getPath(): 获取File对象的封装路径 (创建对象时传入的路径)
        System.out.println(new File("a.txt").getPath());  // 创建对象时是什么路径, 获取的就是什么
        System.out.println(new File("d:\\a.txt").getPath());

        // String getName(): 获取File对象的文件名或目录名
        File f3 = new File("a\\b\\c\\d.txt");
        System.out.println(f3.getName());

        // long length(): 获取File表示的文件大小的字节数 (不能获取目录的大小)
        File f4 = new File("day08\\src\\com\\itheima\\test02\\Test.java");  // 相对路径
        System.out.println(f4.length());  // 1431
    }
}


File类: 判断方法
       java.io.File类
             // 常用判断方法
        boolean exists(): 判断File对象代表的文件或目录是否实际存在
        boolean isDirectory(): 判断File表示的是否为目录
        boolean isFile(): 判断File表示的是否为文件

[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        // boolean exists(): 判断File对象代表的文件或目录是否实际存在
        File f1 = new File("day08\\src");
        System.out.println(f1.exists());

        // boolean isDirectory(): 判断File表示的是否为目录
        File f2 = new File("day08\\src\\com\\itheima\\test03");
        System.out.println(f2.isDirectory());

        // boolean isFile(): 判断File表示的是否为文件
        File f3 = new File("day08\\src\\com\\itheima\\test03\\Test.java");
        System.out.println(f3.isFile());
    }
}


File类: 创建删除方法
java.io.File类
    // 常用创建删除方法
        boolean createNewFile(): 当文件不存在时, 创建一个新的空文件
        boolean delete(): 删除由此File表示的文件或目录. (删除目录时必须是空目录)
        boolean mkdir(): 创建File表示的目录
        boolean mkdirs(): 创建File表示的多级目录

[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) throws IOException {
        // 在当前的模块中创建a目录
       /* File dirA = new File("day08\\a");
        dirA.mkdir();

        // 在a目录中创建b目录
        File dirB = new File("day08\\a\\b");
        dirB.mkdir();*/

        // 以上两步可以合并为一步
        File dirAB = new File("day08\\a\\b");
        dirAB.mkdirs();

        // 在b目录中创建b.txt文件和c.txt文件
        File fileB = new File("day08\\a\\b\\b.txt");
        fileB.createNewFile();
        File fileC = new File("day08\\a\\b\\c.txt");
        fileC.createNewFile();

        // 删除c.txt文件
        fileC.delete();
         
        boolean result = new File("z:\\a").mkdirs();  // 磁盘不存在, 不会创建
        System.out.println(result);  // false
    }
}


File类: 遍历目录方法
java.io.File类
    // 常用获取目录中内容的方法
        String[] list(): 获取当前File目录下的所有子文件或目录的名字数组
        File[] listFiles(): 获取当前File目录中的所有子文件或目录的File对象数组

注意:
        只能用表示目录的File对象调用
        用文件的File对象, 或者路径不存在, 调用会报错

[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        // 创建File对象指向当前模块
        File module = new File("day08");

        // listFiles()获取当前目录中的子文件和子目录的File数组
        File[] files = module.listFiles();
        for (File file : files) {
            System.out.println(file);
        }

        // list(): 获取当前目录中的子文件和子目录的文件名数组
        String[] list = module.list();
        for (String s : list) {
            System.out.println(s);
        }
    }
}

05 - 递归
递归的分类:
        直接递归: 方法自己调用方法
        间接递归: A方法调用B方法, B方法调用C方法, C方法调用A方法

递归打印多级目录
[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        File dir = new File("day08");
        print(dir);
    }

    // 定义方法: 打印某个目录中所有路径
    public static void print(File dir) {  // 传入要打印的目录的File对象
        // 先打印当前目录的路径
        System.out.println(dir);

        // 获取当前目录中的所有子文件和子目录
        File[] files = dir.listFiles();
        // 遍历数组
        for (File file : files) {
            // file代表子文件或者子目录, 具体是什么还需要判断
            if (file.isFile()) {
                // 如果是文件, 则打印文件
                System.out.println(file);
            } else {
                // 如果是目录, 则递归调用当前方法, 打印"该子目录"中的所有路径
                print(file);  // 注意传入的是子目录对象!!!!!
            }
        }
    }
}


打印某个目录下所有java文件路径
[Java] 纯文本查看 复制代码
public class Test {    

public static void main(String[] args) {
        print(new File("day08"));   

}   

// 定义方法: 打印某个目录中的.java文件   

public static void print(File dir) {

       // 先获取当前目录中的所有文件
        File[] files = dir.listFiles();        

// 遍历
        for (File file : files) {
            // 判断是文件还是目录

           if (file.isFile()) {
                // 是文件, 判断后缀
                if (file.getName().toLowerCase().endsWith(".java")) {
                    // 是java文件, 打印
                    System.out.println(file);

               }            

} else if (file.isDirectory()) {               

// 是目录, 递归调用方法
                print(file);
            }

       }

   }}

FileFilter文件过滤器的使用和Lambda优化
[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) {
        print(new File("day08"));
    }

    // 打印指定目录中的.java文件
    public static void print(File dir) {
        // 获取当前目录中的文件, 使用过滤器
        /*File[] files = dir.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return new File(dir, name).isDirectory() || name.toLowerCase().endsWith(".java");
            }
        });*/

        // 使用Lambda表达式简化
        File[] files = dir.listFiles((d, name) -> new File(d, name).isDirectory() || name.toLowerCase().endsWith(".java"));

        // 遍历
        for (File file : files) {
            if (file.isFile()) {
                // 是文件, 则打印
                System.out.println(file);
            } else if (file.isDirectory()) {
                // 是目录, 则递归
                print(file);
            }
        }
    }
}

06 -   IO流
IO流: 输入(Input)输出(Output)流
流: 数据流

输入: 从硬盘(文件)读取到内存(Java程序)
输出: 从内存(Java程序)写入到硬盘(文件)
        (入和出都是相对于内存来说的)

IO流的分类:
    字节流 (读写字节: byte, 可以读写所有类型的文件, 包括视频, 图片, 音频, 文本等)
        字节输入流: java.io.InputStream 抽象类
        字节输出流: java.io.OutputStream 抽象类

    字符流 (读写字符: char, String, 只能读写文本文件)
        字符输入流: java.io.Reader 抽象类
        字符输出流: java.io.Writer 抽象类

java.io.OutputStream抽象类: 字节输出流 (顶层类)
       // 成员方法
        void close() :释放资源
        void flush() :刷新缓冲区(对于字节流来说没有作用)
        // 写字节的成员方法
        abstract void write(int b): 一次写一个字节 (参数int便于传递byte的整数不用强转)
        void write(byte[] b): 一次写一个字节数组
        void write(byte[] b, int offset, int len): 一次写一个字节数组的一部分

        
java.io.FileOutputStream类: 文件字节输出流 (向文件写数据)
        // 构造方法
        FileOutputStream(String name): 通过文件路径创建文件字节输出流
        FileOutputStream(File file): 通过File对象创建文件字节输出流

        构造方法的作用:
                1. 创建一个FileOutputStream对象
                2. 根据构造方法传递的路径, 在磁盘上创建一个空文件 ("如果文件存在则会清空数据")
                3. 将创建的FileOutputStream对象指向这个磁盘上的文件

字节输出流: 一次写一个字节到文件
写数据的原理:
        Java程序 -> JVM虚拟机 -> OS操作系统 -> OS调用写数据的方法 -> 将数据写入文件
使用FileOutputStream写数据到文件
[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) throws IOException {  // 异常先声明抛出
        // 1. 创建流对象
        FileOutputStream fos = new FileOutputStream("day09\\testOutputStream1.txt");
        // 2. 写数据
        fos.write(97);
        fos.write(98);
        fos.write(99);
        // 3. 释放资源
        fos.close();
    }
}


java.io.FileOutputStream类: 文件字节输出流
        // 带有 续写 功能的构造方法, 不会清空文件
        FileOutputStream(String name, boolean append): 通过文件路径创建流, true可以续写
        FileOutputStream(File file, boolean append): 通过File对象创建流, true可以续写

[Java] 纯文本查看 复制代码
public class Test {
    public static void main(String[] args) throws IOException {
        // 创建流对象
        FileOutputStream fos = new FileOutputStream("day09\\testOutputStream2.txt", true);//true或flase
        // 循环写入
        for (int i = 0; i < 5; i++) {
            fos.write("你好".getBytes());
            fos.write("\r\n".getBytes());
        }

        // 释放资源
        fos.close();
    }
}







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