TongHui的博客 - JavaSE
type: channel
link: https://tonghui.domcer.com/index.php/category/JavaSE/
description: JavaSE
items: 多线程基础
items: IO流
items: IO流-总结
items: 字符集
items: 集合概述和分类
items: 正则表达式
items: 异常
items: 冒泡排序、选择排序和查找算法
items: Java8新特性之方法引用
items: Java8新特性之Lambda表达式

多线程基础
type: item
date: 2023-06-13T19:55:19+08:00
description: 多线程基础相关概念多线程多线程就是同时执行多个应用程序 需要硬件支持效果上来说就是CPU在多个程序之间快速切换 给人一种多个软件同时执行的感觉并发: 某一个时刻 多个任务同时在执行 在同一时刻 有多个指令在多个CPU上同时执行并发: 某个时间段 多个任务同时执行 但是某个时刻只有一个任务在执行 在某一时间段 有多个指令在单个CPU上交替执行当下电脑执行过程中两种情况会同时存在并发: 是因为目前的cpu都是多核心的 每个核心执行一个指令多个核心就同时在执行多个指令并发:每个核心在某一刻 只能执行一个程序指令 之后某一刻 可能在执行其他软件的命令进程正在运行的软件独立性 进程是一个能独立运行的基本单位 同时也是系统分配资源和调度的独立单位动态性 进程的是指是程序的一次执行过程 进程是动态产生的 动态消亡的并发性 任何进程都可以同其他进程一起并发执行线程是进程中的单个循序控制流 是一条执行路径 应用程序中能做的某个事情随机性: 一个宪曾在某个时间段内在执行 但是这段时间的某个时刻不一定在执行 此时cpu可以能在执行另一个软件 cpu可以在多个线程 随机快速切换执行多线程的实现方式jdk原生支持的1.继承thread类2.实现runnable接口3.实现callable接口继承Thread类方法void run()想要多线程中执行的代码写在这个方法中 在线程启动后此方法将自动被调用执行void start()启动线程的方法 之后java虚拟机会调用run()方法实现步骤定义一个类MyThread继承Thread类在MyThread类中重写run()方法创建MyThread类的对象使用线程对象的start()启动线程public class ThreadDemo01 { public static void main(String[] args) { // 3. 创建MyThread类的对象 MyThread mth1 = new MyThread(); MyThread mth2 = new MyThread(); // 4. 使用线程对象的start()启动线程 mth1.start(); mth2.start(); } } // 1. 定义一个类MyThread继承Thread类 class MyThread extends Thread{ @Override // 2. 在MyThread类中重写run()方法 public void run() { // 这里的代码会在对应的线程启动后自动被执行 for (int i = 0; i < 100; i++) { System.out.println("新的线程开始执行代码了"+i); } } } 重点解析问:为什么要冲洗run()方法因为run()是用封装被线程执行代码的 我们可以想要在多线程环境下运行的代码写在run()方法中 这些代码可以称之为任务问: run()方法和start()方法的区别run() 封装多线程执行的代码 封装任务代码的如果直接调用该方法 就是main方法线程中执行普通方法 也就是普通方法的调用start() 启动线程开启一个新线程 在新县城中执行代码 由jvm调用此线程的run方法执行run中的任务代码实现Runnalbe接口Thread构造方法Thread(Runnable target) 分配一个新的Thread对象Thread(Runnable target,String name) 分配一个新的Thread对象Runnable接口中方法run() 任务方法内部编写要在多线程环境下执行的代码实现步骤定义一个类MyRunnable实现Runnale接口在Myrunnable类中重写run()方法 编写需要在多线程环境下运行的代码

IO流
type: item
date: 2021-05-19T16:53:00+08:00
description: 概念IO：输入/输出(Input/Output)，视角为内存视角。流：是一种抽象概念，是对数据传输的总称。也就是说数据在设备间的传输称为流，流的本质是数据传输IO流就是用来处理设备间数据传输问题的。常见的应用场景: 文件复制; 文件上传; 文件下载、文件查看IO流的分类按照数据的流向输入流：读数据输出流：写数据按照数据类型来分字节流(万能流)字节输入流（InputStream）字节输出流（OutputStream）字符流字符输入流（Reader）字符输出流（Writer）字符流指的是传递字符的流，建议只用于读写纯文本文件；纯文本文件：如果某个文件用系统自带的记事本打开并且能够轻松看懂，就是纯文本文件。字节流指的是传递字节的流，可以读写任意文件。又称万能流。3. 字节流字节流就是以字节为单位操作数据的流。3.1 字节输出流：写3.1.1 基本使用：写一个字节相关方法说明方法签名说明FileOutputStream FileOutputStream(File file)基于一个File封装一个FileOutputStream对象FileOutputStream FileOutputStream(String pathName)基于一个字符串格式的文件路径封装一个FileOutputStream对象void write(int b)把指定的内容写入文件void close()关闭流释放资源 三个步骤创建字节输出流(FileOutputStream)对象写出数据关闭流释放资源注释// FileOutputStream FileOutputStream(String pathName) 基于一个字符串格式的文件路径封装一个FileOutputStream对象 // FileOutputStream FileOutputStream(File file) 基于一个File封装一个FileOutputStream对象 // void write(int b) 把指定的内容写入文件 // void close() 关闭流释放资源演示代码 /** * 字节输出流入门案例：写一个字节 */ public class ByteStreamDemo01 { public static void main(String[] args) throws IOException { // FileOutputStream FileOutputStream(String pathName) 基于一个字符串格式的文件路径封装一个FileOutputStream对象 // FileOutputStream FileOutputStream(File file) 基于一个File封装一个FileOutputStream对象 // void write(int b) 把指定的内容写入文件 // void close() 关闭流释放资源 // 创建自己输入流对象 // 创建输出流对象时，会判断关联的文件是否存在； // 如果不存在，会自动创建一个空白的文件 // 如果存在，则清空文件内容 FileOutputStream fos = new FileOutputStream("d:\\file\\a.txt"); // 写出数据 // 字节输入流，操作的是字节；写97其实写的不是97这两个字符，而是一个码点/码值； // 程序会把他当做一个字节写入到文件。我们查看，把这个字节的数字作为码点，查询字符集中对应的字符，后展示。 fos.write(98); // 关闭流释放资源 // 创建输入流对象时，会自动关联对应的文件；这个时候，可以理解为当前这个Java程序独占了该文件 // 其他的程序想要操作相同文件时，会有问题。 // 所以使用完之后，要关闭流，释放对文件的独占 fos.close(); } }3.1.2 写入一个字节数组相关方法说明方法签名说明void write(int b)一次写一个字节数据(编码值)到指定位置（文件）void write(byte[] b)一次写一个字节数组数据到指定位置（文件）void write(byte[] b,int off,int len)一次写一个字节数组的部分到指定位置（文件）注释// void write(byte[] b) 一次写一个字节数组数据到指定位置（文件） // void write(byte[] b,int off,int len)一次写一个字节数组的部分到指定位置（文件） 演示代码 public class ByteSteamDemo01 { public static void main(String[] args) throws IOException { // 1. 创建字节输出流(`FileOutput…

IO流-总结
type: item
date: 2021-05-18T19:49:00+08:00
description: Java中的IO流主要分为四类：字节流、字符流、字节缓冲流和字符缓冲流输入和输出字符流字符流是专门为读取文本数据而生的FileReader类这是字符输入流，用来将文件中的字符数据读取到程序中来创建字符输入流通道FileReader(File file) 创建字符输入流管道与源文件接通 FileReader(String pathname) 创建字符输入流管道与源文件接通FileReader读取文件的步骤如下：//第一步：创建FileReader对象与要读取的源文件接通 //第二步：调用read()方法读取文件中的字符 //第三步：调用close()方法关闭流read()每次读取一个字符返回,没有发现没有数据可读会返回-1read(char[] buffer)每次会一个字符数组去读取数据,返回字符数读取了多少个字符,如果没有发现数据可读会返回-1read()的应用public class FileReaderTest1 { public static void main(String[] args) { try ( // 1、创建一个文件字符输入流管道与源文件接通 Reader fr = new FileReader("text.txt"); ){ // 2、一个字符一个字符的读（性能较差） // 记住每次读取的字符编号。 int c; while ((c = fr.read()) != -1){ System.out.print((char) c); } } catch (Exception e) { e.printStackTrace(); } } }read(byte[] buffer)的应用public class FileReaderTest1 { public static void main(String[] args) { try ( //创建一个文件字符输入流管道与源文件接通 Reader fr = new FileReader("io-app2\\src\\itheima01.txt"); ){ //每次读取多个字符。（性能是比较不错的！） char[] buffer = new char[3]; int len; // 记住每次读取了多少个字符。 while ((len = fr.read(buffer)) != -1){ // 读取多少倒出多少 System.out.print(new String(buffer, 0, len)); } } catch (Exception e) { e.printStackTrace(); } } }FileWriter类它可以将程序中的字符数据写入文件FileWriter往文件中写字符数据的步骤如下：第一步：创建FileWirter对象与要读取的目标文件接通 第二步：调用write(字符数据/字符数组/字符串)方法读取文件中的字符 第三步：调用close()方法关闭流创建字节输出流管道与源文件对象接通//会覆盖原文件内容 FileWriter(File file) 创建字节输出流管道与源文件对象接通 FileWirter(String filePath) 创建字节输出流管道与源文件对象接通 //可以追加内容 FileWriter(File file,boolean append) 创建字节输出流管道与源文件对象接通 可以追加内容 FileWirter(String filePath,boolean append) 创建字节输出流管道与源文件对象接通 可以追加内容write(int c)写一个字符write(String str)写一个字符串write(String str,int off,int len)写一个字符串的一部分wirte(char[] cbuf)写入一个字符数组wirte(char[] cbuf,int off,int len)写入字符数组的一部分前提try ( // 0、创建一个文件字符输出流管道与目标文件接通。 // 覆盖管道 // Writer fw = new FileWriter("io-app2/src/itheima02out.txt"); // 追加数据的管道 Writer fw = new FileWriter("io-app2/src/itheima02out.txt", true); ){ //下面内容 } catch (Exception e) { e.printStackTrace(); }write(int c)的应用// 1、public void write(int c):写一个字符出去 fw.write('a'); fw.write(97); //fw.write('磊'); // 写一个字符出去 fw.write("…

字符集
type: item
date: 2021-05-18T16:43:00+08:00
description: 字符集计算机只能处理0和1组成的二进制数据，为了让计算机能够存储处理字符，计算机的设计者美国人就把他们会用到的每一个字符进行了编码（所谓编码，就是人为的为每一个字符关联一个数字（称为码点）），计算机在存储某个字符时，存储的就是字符对应码点的二进制数据。ASCII字符集：《美国信息交换标准代码》，包含英文字母、数字、标点符号、控制字符 特点：1个字符占1个字节 GBK字符集：中国人自己的字符集，兼容ASCII字符集，还包含2万多个汉字 特点：1个字母占用1个字节；1个汉字占用2个字节 Unicode字符集：包含世界上所有国家的文字，有三种编码方案，最常用的是UTF-8 UTF-8编码方案：英文字母、数字占1个字节兼容(ASCII编码)、汉字字符占3个字节相关方法（String类中方法） 方法名说明编byte[] getBytes()使用平台的默认字符集将一个字符串编码为字节数组码byte[] getBytes(String charsetName)使用指定的字符集将一个字符串编码为字节数组解String(byte[] bytes)使用平台的默认字符集解码指定的字节数组来创建字符串码String(byte[] bytes, String charsetName)通过指定的字符集解码指定的字节数组来创建字符串注释// byte[] getBytes () 使用平台的默认字符集将一个字符串编码为字节数组 // byte[] getBytes (String charsetName)使用指定的字符集将一个字符串编码为字节数组 // String( byte[] bytes)使用平台的默认字符集解码指定的字节数组来创建字符串 | // String( byte[] bytes, String charsetName)通过指定的字符集解码指定的字节数组来创建字符串public static void main(String[] args) throws UnsupportedEncodingException { // byte[] getBytes () 使用平台的默认字符集将一个字符串编码为字节数组 // byte[] getBytes (String charsetName)使用指定的字符集将一个字符串编码为字节数组 // String( byte[] bytes)使用平台的默认字符集解码指定的字节数组来创建字符串 | // String( byte[] bytes, String charsetName)通过指定的字符集解码指定的字节数组来创建字符串 // 1. 编码 // 从字符串 -> 码点数字 String str1 = "中国"; // byte[] getBytes () 使用平台的默认字符集将一个字符串编码为字节数组 byte[] str1U8Bytes = str1.getBytes(); // str1U8Bytes = [-28, -72, -83, -27, -101, -67] System.out.println("str1U8Bytes = " + Arrays.toString(str1U8Bytes)); // byte[] getBytes (String charsetName)使用指定的字符集将一个字符串编码为字节数组 byte[] strGbkBytes = str1.getBytes("GBK"); // strGbkBytes = [-42, -48, -71, -6] System.out.println("strGbkBytes = " + Arrays.toString(strGbkBytes)); // 2.解压 // 从 码点数字(字节数组) -> 字符串 ====> 字符串构造方法 // 使用默认字符集：U8 // String( byte[] bytes)使用平台的默认字符集解码指定的字节数组来创建字符串 String str2 = new String(new byte[]{-28, -72, -83, -27, -101, -67}); // str2 = 中国 System.out.println("str2 = " + str2); // 使用指定字符集:GBK // String( byte[] bytes, String charsetName)通过指定的字符集解码指定的字节数组来创建字符串 String str3 = new String(new byte[]{-42, -48, -71, -6},"gbk"); // str3 = 中国 System.out.println("str3 = " + str3); // 演示乱码 // 编解码使用不同的字符集：UT…

集合概述和分类
type: item
date: 2021-05-17T17:38:00+08:00
description: 集合概述和分类集合的分类前面我们已经学习过了ArrayList集合，但是除了ArrayList集合，Java还提供了很多种其他的集合，如下图所示：这些集合一共分两大类，如下图所示：一类是单列集合元素是一个一个的，另一类是双列集合元素是一对一对的。主要学习Collection单列集合。Collection是单列集合的根接口，Collection接口下面又有两个子接口List接口、Set接口，List和Set下面分别有不同的实现类，如下图所示：上图中各种集合的特点如下图所示：可以自己写代码验证一下，各种集合的特点//简单确认一下Collection集合的特点 ArrayList<String> list = new ArrayList<>(); //存取顺序一致，可以重复，有索引 list.add("java1"); list.add("java2"); list.add("java1"); list.add("java2"); System.out.println(list); //[java1, java2, java1, java2] HashSet<String> list = new HashSet<>(); //存取顺序不一致，不重复，无索引 list.add("java1"); list.add("java2"); list.add("java1"); list.add("java2"); list.add("java3"); System.out.println(list); //[java3, java2, java1] Collection集合的常用方法Collection集合的一些常用方法，这些方法所有Collection实现类都可以使用。 这里我们以创建ArrayList为例，来演示Collection<String> c = new ArrayList<>(); //1.public boolean add(E e): 添加元素到集合 c.add("java1"); c.add("java1"); c.add("java2"); c.add("java2"); c.add("java3"); System.out.println(c); //打印: [java1, java1, java2, java2, java3] //2.public int size(): 获取集合的大小 System.out.println(c.size()); //5 //3.public boolean contains(Object obj): 判断集合中是否包含某个元素 System.out.println(c.contains("java1")); //true System.out.println(c.contains("Java1")); //false //4.pubilc boolean remove(E e): 删除某个元素，如果有多个重复元素只能删除第一个 System.out.println(c.remove("java1")); //true System.out.println(c); //打印: [java1,java2, java2, java3] //5.public void clear(): 清空集合的元素 c.clear(); System.out.println(c); //打印：[] //6.public boolean isEmpty(): 判断集合是否为空 是空返回true 反之返回false System.out.println(c.isEmpty()); //true //7.public Object[] toArray(): 把集合转换为数组 Object[] array = c.toArray(); System.out.println(Arrays.toString(array)); //[java1,java2, java2, java3] //8.如果想把集合转换为指定类型的数组，可以使用下面的代码 String[] array1 = c.toArray(new String[c.size()]); System.out.println(Arrays.toString(array1)); //[java1,java2, java2, java3] //9.还可以把一个集合中的元素，添加到另一个集合中 Collection<String> c1 = new ArrayList<>(); c1.add("java1"); c1.add("java2"); Collection<String> c2 = new ArrayList<>(); c2.add("java3")…

正则表达式
type: item
date: 2021-05-17T17:30:00+08:00
description: 正则表达式正则表达式其实是由一些特殊的符号组成的，它代表的是某种规则。正则表达式的作用1：用来校验字符串数据是否合法正则表达式的作用2：可以从一段文本中查找满足要求的内容正则表达式初体验现在，我们就以QQ号码为例，来体验一下正则表达式的用法。注意：现在仅仅只是体验而已，我们还没有讲正则表达式的具体写法。不使用正则表达式，校验QQ号码代码是这样的public static boolean checkQQ(String qq){ // 1、判断qq号码是否为null if(qq == null || qq.startsWith("0") || qq.length() < 6 || qq.length() > 20){ return false; } // 2、qq至少是不是null,不是以0开头的，满足6-20之间的长度。 // 判断qq号码中是否都是数字。 // qq = 2514ghd234 for (int i = 0; i < qq.length(); i++) { // 根据索引提取当前位置处的字符。 char ch = qq.charAt(i); // 判断ch记住的字符，如果不是数字，qq号码不合法。 if(ch < '0' || ch > '9'){ return false; } } // 3、说明qq号码肯定是合法 return true; }用正则表达式代码是这样的public static boolean checkQQ1(String qq){ return qq != null && qq.matches("[1-9]\\d{5,19}"); }使用正则表达式，大大简化的了代码的写法。正则表达式书写规则前面我们已经体验到了正则表达式，可以简化校验数据的代码书写。这里需要用到一个方法叫matches(String regex)。这个方法时属于String类的方法。这个方法是用来匹配一个字符串是否匹配正则表达式的规则，参数需要调用者传递一个正则表达式。但是正则表达式不能乱写，是有特定的规则的。下面我们就学习一下，正则表达式的规则。从哪里学呢？在API中有一个类叫做Pattern，我们可以到API文档中搜索，关于正则表达式的规则，这个类都告诉我们了。我这里把常用的已经给大家整理好了。我们将这些规则，在代码中演示一下/** * 目标：掌握正则表达式的书写规则 */ public class RegexTest2 { public static void main(String[] args) { // 1、字符类(只能匹配单个字符) System.out.println("a".matches("[abc]")); // [abc]只能匹配a、b、c System.out.println("d".matches("[^abc]")); // [^abc] 不能是abc // 2、预定义字符(只能匹配单个字符) . \d \D \s \S \w \W // \转义 System.out.println("\""); // \n \t System.out.println("3".matches("\\d")); // \d: 0-9 System.out.println("a".matches("\\d")); //false // 3、数量词： ? * + {n} {n, } {n, m} System.out.println("1".matches("[0-9]?")); // ? 代表0次或1次 System.out.println("123".matches("[0-9]*")); // * 代表0次或多次 } }正则表达式应用案例学习完正则表达式的规则之后，我们看几个实际案例。正则表达式校验手机号码/** * 目标：校验用户输入的电话、邮箱、时间是否合法。 */ public class RegexTest3 { public static void main(String[] args) { checkPhone(); } public static void checkPhone(){ while (true) { System.out.println("请您输入您的电话号码(手机|座机): "); Scanner sc = new Scanner(System.in); String phone = sc.nextLine(); // 1. 手机号码，以1开头，第二位是3-9中的任意一个数字，后面跟着9个数字。 // 2. 座机号码，以0开头，后面跟着2-7位数字，然后可能会有一个横杠（“-”），后面是4-19位数字。 if(phone.matches("(1[3-9]\\d{9})|(0\\d{…

异常
type: item
date: 2021-05-16T17:34:00+08:00
description: 认识异常我们调用一个方法时，经常一不小心就出异常了，然后在控制台打印一些异常信息。其实打印的这些异常信息，就叫做异常。异常的继承体系1.1.2演示运行时异常int[] arr = {11,22,33}; //5是一个不存在的索引，所以此时产生ArrayIndexOutOfBoundsExcpetion System.out.println(arr[5]); 下图是API中对ArrayIndexOutOfBoundsExcpetion类的继承体系，以及告诉我们它在什么情况下产生。1.1.3演示编译时异常编译时异常，它把异常的提醒提前了，你调用方法是否真的有问题，只要可能有问题就给你报出异常提示（红色波浪线）。编译时异常的目的：意思就是告诉你，你小子注意了！！，这里小心点容易出错，仔细检查一下1.1.4认识异常处理有人说，我检查过了，我确认我的代码没问题，为了让它不报错，继续将代码写下去。我们这里有两种解决方案。第一种：使用throws在方法上声明，意思就是告诉下一个调用者，这里面可能有异常啊，你调用时注意一下。/** * 目标：认识异常。 */ public class ExceptionTest1 { public static void main(String[] args) throws ParseException{ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date d = sdf.parse("2028-11-11 10:24"); System.out.println(d); } }第二种：使用try...catch语句块异常进行处理。public class ExceptionTest1 { public static void main(String[] args) throws ParseException{ try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date d = sdf.parse("2028-11-11 10:24"); System.out.println(d); } catch (ParseException e) { e.printStackTrace(); } } }1.2 自定义异常Java提供了一些异常，但是Java官方无法为这个世界上的全部问题都提供异常类，如果企业自己的某种问题，想通过异常来表示，那就需要自己来定义异常类了。我们通过一个实际场景，来给大家演示自定义异常。需求：写一个saveAge(int age)方法，在方法中对参数age进行判断，如果age<0或者>=150就认为年龄不合法，如果年龄不合法，就给调用者抛出一个年龄非法异常。分析：Java的API中是没有年龄非常这个异常的，所以我们可以自定义一个异常类，用来表示年龄非法异常，然后再方法中抛出自定义异常即可。先写一个异常类AgeIllegalException（这是自己取的名字，名字取得很奈斯），继承// 1、必须让这个类继承自Exception，才能成为一个编译时异常类。 public class AgeIllegalException extends Exception{ public AgeIllegalException() { } public AgeIllegalException(String message) { super(message); } }再写一个测试类，在测试类中定义一个saveAge(int age)方法，对age判断如果年龄不在0~150之间，就抛出一个AgeIllegalException异常对象给调用者。public class ExceptionTest2 { public static void main(String[] args) { // 需求：保存一个合法的年 try { saveAge2(225); System.out.println("saveAge2底层执行是成功的！"); } catch (AgeIllegalException e) { e.printStackTrace(); System.out.println("saveAge2底层执行是出现bug的！"); } } //2、在方法中对age进行判断，不合法则抛出AgeIllegalException public static void saveAge(int age){ if(age > 0 && age < 150){ System.out.println("年龄被成功保存： " + age); }els…

冒泡排序、选择排序和查找算法
type: item
date: 2021-05-16T17:23:00+08:00
description: 1.1 认识算法算法是解决某个实际问题的过程和方法。比如百度地图给你规划路径，计算最优路径的过程就需要用到算法。再比如你在抖音上刷视频时，它会根据你的喜好给你推荐你喜欢看的视频，这里也需要用到算法。作为java程序员，我们日常几乎用不到算法，只需要学习几种常见的基础算法就可以了。而且Java语言本身就内置了一些基础算法给我们使用，实际上自己也不会去写这些算法。我们为什么要学习算法呢？算法可以锻炼我们的编程思维。1.2 冒泡排序(重要)接下来，我们学习一种算法叫排序算法，它可以价格无序的整数，排列成从小到大的形式（升序），或者从大到小的形式（降序）学习算法我们先要搞清楚算法的流程，然后再去“推敲“如何写代码。（注意，我这里用的次是推敲，也就是说算法这样的代码并不是一次成型的，是需要反复修改才能写好的**）。先来学习冒泡排序，先来介绍一下，冒泡排序的流程冒泡排序核心思路：每次将相邻的两个元素继续比较 如下图所示： 第一轮比较 3次 第二轮比较 2次 第三轮比较 1次public class Test1 { public static void main(String[] args) { // 1、准备一个数组 int[] arr = {5, 2, 3, 1}; // 2、定义一个循环控制排几轮 for (int i = 0; i < arr.length - 1; i++) { // i = 0 1 2 【5， 2， 3， 1】 次数 // i = 0 第一轮 0 1 2 3 // i = 1 第二轮 0 1 2 // i = 2 第三轮 0 1 // 3、定义一个循环控制每轮比较几次。 for (int j = 0; j < arr.length - i - 1; j++) { // 判断当前位置的元素值，是否大于后一个位置处的元素值，如果大则交换。 if(arr[j] > arr[j+1]){ int temp = arr[j + 1]; arr[j + 1] = arr[j]; arr[j] = temp; } } } System.out.println(Arrays.toString(arr)); } } 选择排序我们先分析选择排序算法的流程：选择排序的核心思路是，每一轮选定一个固定的元素，和其他的每一个元素进行比较；经过几轮比较之后，每一个元素都能比较到了。接下来，按照选择排序的流程编写代码ublic class Test2 { public static void main(String[] args) { // 1、准备好一个数组 int[] arr = {5, 1, 3, 2}; // 0 1 2 3 // 2、控制选择几轮 for (int i = 0; i < arr.length - 1; i++) { // i = 0 第一轮 j = 1 2 3 // i = 1 第二轮 j = 2 3 // i = 2 第三轮 j = 3 // 3、控制每轮选择几次。 for (int j = i + 1; j < arr.length; j++) { // 判断当前位置是否大于后面位置处的元素值，若大于则交换。 if(arr[i] > arr[j]){ int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } } System.out.println(Arrays.toString(arr)); } }查找算法1.3 查找算法接下来，我们学习一个查找算法叫做二分查找。在学习二分查找之前，我们先来说一下基本查找，从基本查找的弊端，我们再引入二分查找，这样我们的学习也会更加丝滑一下。先聊一聊基本查找：假设我们要查找的元素是81，如果是基本查找的话，只能从0索引开始一个一个往后找，但是如果元素比较多，你要查找的元素比较靠后的话，这样查找的此处就比较多。性能比较差。再讲二分查找：二分查找的主要特点是，每次查找能排除一般元素，这样效率明显提高。但是二分查找要求比较苛刻，它要求元素必须是有序的，否则不能进行二分查找。二分查找的核心思路第1步：先定义两个变量，分别记录开始索引(left)和结束索引(right) 第2步：计算中间位置的索引，mid = (left+right)/2; 第3步：每次查找中间mid位置的元素，和目标元素key进行比较 如果中间位置元素比目标元素小，那就说明mid前面的元素都比目标元素小 此时：left = mid+1 如果中间位置元素比目标元素大，那说明mid后面的元素都比目标元素大 此时：right = mid-1 如果中间位置元素和目标元素相等，那说明mid就是我们要找的位置 此时：把mid返回 注意：一搬查找一次肯定是不够的，所以需要把第1步和第…

Java8新特性之方法引用
type: item
date: 2021-05-16T17:20:00+08:00
description: Lambda是用来简化匿名代码的书写格式的，而方法引用是用来进一步简化Lambda表达式的，它简化的更加过分。静态方法引用准备好下面的代码public class Test1 { public static void main(String[] args) { Student[] students = new Student[4]; students[0] = new Student("蜘蛛精", 169.5, 23); students[1] = new Student("紫霞", 163.8, 26); students[2] = new Student("紫霞", 163.8, 26); students[3] = new Student("至尊宝", 167.5, 24); // 原始写法：对数组中的学生对象，按照年龄升序排序 Arrays.sort(students, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return o1.getAge() - o2.getAge(); // 按照年龄升序排序 } }); // 使用Lambda简化后的形式 Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge()); } }准备另外一个类CompareByData类，用于封装Lambda表达式的方法体代码；public class CompareByData { public static int compareByAge(Student o1, Student o2){ return o1.getAge() - o2.getAge(); // 升序排序的规则 } }现在我们就可以把Lambda表达式的方法体代码，改为下面的样子Arrays.sort(students, (o1, o2) -> CompareByData.compareByAge(o1, o2));Java为了简化上面Lambda表达式的写法，利用方法引用可以改进为下面的样子。实际上就是用类名调用方法，但是把参数给省略了。这就是静态方法引用//静态方法引用：类名::方法名 Arrays.sort(students, CompareByData::compareByAge);总结一下，当在Lambda表达式中使用静态方法时，可以使用 类名::方法名 的方式，而这就是静态方法引用

Java8新特性之Lambda表达式
type: item
date: 2021-05-15T17:18:00+08:00
description: 我们学习一个JDK8新增的一种语法形式，叫做Lambda表达式。作用：用于简化匿名内部类代码的书写。**Lambda表达式基本使用怎么去简化呢？Lamdba是有特有的格式的，按照下面的格式来编写Lamdba。(被重写方法的形参列表) -> { 被重写方法的方法体代码; }需要给说明一下的是，在使用Lambda表达式之前，必须先有一个接口，而且接口中只能有一个抽象方法。（注意：不能是抽象类，只能是接口）像这样的接口，我们称之为函数式接口，只有基于函数式接口的匿名内部类才能被Lambda表达式简化。public interface Swimming{ void swim(); }有了以上的Swimming接口之后，接下来才能再演示，使用Lambda表达式，简化匿名内部类书写。public class LambdaTest1 { public static void main(String[] args) { // 目标：认识Lambda表达式. //1.创建一个Swimming接口的匿名内部类对象 Swimming s = new Swimming(){ @Override public void swim() { System.out.println("学生快乐的游泳~~~~"); } }; s.swim(); //2.使用Lambda表达式对Swimming接口的匿名内部类进行简化 Swimming s1 = () -> { System.out.println("学生快乐的游泳~~~~"); }; s1.swim(); } }好的，我们现在已经知道Lamdba表达式可以简化基于函数式接口的匿名内部类的书写。接下来，我们可以把刚才使用Arrays方法时的代码，使用Lambda表达式简化一下了。public class LambdaTest2 { public static void main(String[] args) { // 目标：使用Lambda简化函数式接口。 double[] prices = {99.8, 128, 100}; //1.把所有元素*0.8: 先用匿名内部类写法 Arrays.setAll(prices, new IntToDoubleFunction() { @Override public double applyAsDouble(int value) { // value = 0 1 2 return prices[value] * 0.8; } }); //2.把所有元素*0.8: 改用Lamdba表达式写法 Arrays.setAll(prices, (int value) -> { return prices[value] * 0.8; }); System.out.println(Arrays.toString(prices)); System.out.println("-----------------------------------------------"); Student[] students = new Student[4]; students[0] = new Student("蜘蛛精", 169.5, 23); students[1] = new Student("紫霞", 163.8, 26); students[2] = new Student("紫霞", 163.8, 26); students[3] = new Student("至尊宝", 167.5, 24); //3.对数组中的元素按照年龄升序排列: 先用匿名内部类写法 Arrays.sort(students, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return Double.compare(o1.getHeight(), o2.getHeight()); // 升序 } }); //4.对数组中的元素按照年龄升序排列: 改用Lambda写法 Arrays.sort(students, (Student o1, Student o2) -> { return Double.compare(o1.getHeight(), o2.getHeight()); // 升序 }); System.out.println(Arrays.toString(students)); } }到这里，你已经学会了Lambda表达式的基本使用了。Lambda表达式省略规则Lambda表达式还可以简化，具体的简化规则如下：1.Lambda的标准格式 (参数类型1 参数名1, 参数类型2 参数名2) -…