集合的排序
Collection.sort()
Collection.sort()方法实现排序
-
Collections是集合的工具类,它提供了很多便于我们操作集合的方法,其中就有用于集合排序的sort方法。
-
该方法定义为:
-
static void sort(List<T> list)
:该方法的作用是对给定的集合元素进行自然排序(升序);降序则为反转自然排序:static void reverse(List<?> list)
;- 该方法要求集合元素必须实现Comparable接口,否则编译不通过。
-
package day15;
import java.util.*;
/**
* Collections.sort():用于对集合元素进行排序
*/
public class SortInteger {
public static void main(String[] args) {
Random random = new Random();
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 10; i++) {
list.add(random.nextInt(100));
}
System.out.println("list的原始数据:" + list);
// 对集合元素进行排序(从小到大)
Collections.sort(list);
System.out.println("list排序后的数据:" + list);
// 对集合元素进行排序(从大到小)
Collections.reverse(list); // 反转list集合(数据已经改变)
System.out.println("list反转后的数据:" + list);
System.out.println("第1个元素是:" + list.get(0));
}
}
-
对英文字符串进行排序
- 操作是一样的,但是对英文字符串进行排序时,会按首字母的ASCII码进行排序,如果首字母相同,测按照第二个字母的首字母ASCII码进行排序。
package day15;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 对字符串进行排序
*/
public class SortString {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("jack");
list.add("tom");
list.add("rose");
list.add("jerry");
list.add("black");
list.add("Kobe");
System.out.println("list的原始数据:" + list); // [[jack, tom, rose, jerry, black, Kobe]]
/**
* 对英文字符串进行排序时,会按首字母的ASCII码进行排序
* 如果首字母相同,则按照第二个字母的ASCII码进行排序,以此类推!
*/
Collections.sort(list);
System.out.println("list排序后的数据:" + list); // [Kobe, black, jack, jerry, rose, tom]
}
}
-
对中文进行排序:
- 按常规方法还是会按默认的ASCII码进行排序,但这不是我们想要的结果:
package day15;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 对字符串进行排序
*/
public class SortString {
public static void main(String[] args) {
/**
* 对字符串进行排序时,用常规方法还是会按汉字的ASCII码进行排序
*/
List<String> list2 = new ArrayList<>();
list2.add("张三");
list2.add("李四");
list2.add("王五");
list2.add("赵六");
list2.add("钱七");
list2.add("孙八");
System.out.println("list2的原始数据:" + list2); // [[张三, 李四, 王五, 赵六, 钱七, 孙八]]
Collections.sort(list2); // 升序排列
System.out.println("list2排序后的数据:" + list2); // [李四, 王五, 孙八, 张三, 赵六, 钱七]
}
}
- 所以我们要通过Comparator接口回调的方式,重载Comparator接口,创建匿名内部类的方式来重写compare()方法,这样可以保证在不创建多余类的前提实现在同一类中只在此处创建自己的排序规则。
package day15;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* 对字符串进行排序
*/
public class SortString {
public static void main(String[] args) {
// 通过重载Comparator创建匿名内部类,重写compare()方法完成自己创建的比较规则
/**
* compare()方法用于定义o1和o2比较大小的规则,并且通过返回值表述大小关系
* 返回值实现的要求:----------不用纠结,记住下面的结论即可
* 1)如果返回值>0则表述的是o1>o2
* 2)如果返回值<0则表述的是o1<o2
* 3)如果返回值=0则表述的是o1=o2
* 结论:
* 1)前面的-后面的------------升序
* 2)后面的-前面的------------降序
*/
Collections.sort(list2, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
// return o1.length() - o2.length(); // 升序
return o2.length() - o1.length(); // 降序
}
});
System.out.println("list2排序后的数据:" + list2); // [扬尼斯阿德托昆博, 科比布莱恩特, 詹姆斯哈登, 深田咏美, 张禹垚, 胡兵]
}
}
- 其实还有一种更为优雅的方法:Lambda表达式!
Lambda表达式
-
Lambda表达式是JDK8之后推出的新特性;
-
Lambda表达式可以更简洁的创建匿名内部类;
-
Lambda表达式的使用:
-
实现的接口有且只能有一个抽象方法;
-
语法:
(参数列表) -> { // 方法体 }
-
使用Lambda表达式可以更专注于逻辑代码,而不必再赘述实现的接口与实现的方法。
-
参数类型可以不写,return关键字必须不写,如果只有一句话那么方法体的话大括号{}也可以不写,如果参数只有一个的话甚至括号也可以不写。我们用Lambda再次改进我们的代码:
package day15; import java.util.*; /** * JDK8之后Java推出了一个新特性:Lambda表达式 * lambda表达式可以使用更简洁的语法来创建匿名内部类 * 但是前提是所实现的接口只有一个抽象方法 --- 函数式接口 * 使用lambda可以重点体现方法的逻辑,使代码更优雅 * 语法:(参数列表) -> {方法体} */ public class LambdaDemo1 { public static void main(String[] args) { List<String> list = new ArrayList<>(); // 匿名内部类写法 Collections.sort(list, new Comparator<String>() { @Override public int compare(String o1, String o2) { return o1.length() - o2.length(); } }); // lambda表达式写法: Collections.sort(list,(String o1, String o2) -> { return o1.length() - o2.length(); }); // lambda表达式中,参数类型可以不写 Collections.sort(list,(o1, o2) -> { return o1.length() - o2.length(); }); // lambda表达式中,如果方法体只有一行代码,可以省略大括号并必须省略return Collections.sort(list,(o1, o2) -> o1.length() - o2.length()); // lambda表达式中,如果参数只有一个,可以省略小括号 --- 本案例不适合 } }
-
排序自定义元素
-
static void sort(List<T> list)
:方法要求集合元素必须实现Comparable接口; -
如果我们这样写:
package day15;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 对Point集合进行排序
*/
public class SortPoint {
public static void main(String[] args) {
List<Point> list = new ArrayList<>();
list.add(new Point(5, 8));
list.add(new Point(33, 290));
list.add(new Point(21, 52));
list.add(new Point(45, 6));
list.add(new Point(55, 69));
list.add(new Point(1, 2));
Collections.sort(list); // 编译错误
}
}
-
对于自定义类型元素,不推荐实现Comparable接口,因为这样的操作对于我们的程序具有侵入性;
- 侵入性:当我们的代码需要引入一个组件,导致其他代码要做相应的改动调整老师应这个组件,这种情况我们就称组件具有侵入性。
package day15;
import day14.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* 对Point集合进行排序
*/
public class SortPoint {
public static void main(String[] args) {
List<Point> list = new ArrayList<>();
list.add(new Point(5, 8));
list.add(new Point(33, 290));
list.add(new Point(21, 52));
list.add(new Point(45, 6));
list.add(new Point(55, 69));
list.add(new Point(1, 2));
System.out.println("list原始数据:" + list); // [(5,8), (33,290), (21,52), (45,6), (55,69), (1,2)]
Collections.sort(list, new Comparator<Point>() {
@Override
public int compare(Point o1, Point o2) {
int len1 = o1.getX() * o1.getX() + o1.getY() * o1.getY();
int len2 = o2.getX() * o2.getX() + o2.getY() * o2.getY();
return len1 - len2; // 升序
// return len2 - len1; // 降序
}
});
Collections.sort(list, (o1, o2) -> {
int len1 = o1.getX() * o1.getX() + o1.getY() * o1.getY();
int len2 = o2.getX() * o2.getX() + o2.getY() * o2.getY();
return len1 - len2; // 升序
// return len2 - len1; // 降序
}
);
System.out.println("list排序后数据:" + list);
}
}
File
创建File对象
File(String pathname)
-
java.io.File用于表示文件或目录,也就是说程序员可以通过File类在程序中操作硬盘上的文件和目录。
-
File类只用于表示文件或目录的信息(名称、大小等)。不能对文件的内容进行访问。
-
构造方法:
-
File(String pathname)
-
通过将给定路径名字符串转换成抽象路径名来创建一个新File实例;
-
抽象路径应尽量使用相对路径,并且目录的层级分隔符不要直接写”/“或”\“,应使用File.separator这个常量表示,以免不同系统带来的差异。
-
-
使用java.io.File有什么用?
-
File的每一个实例用于表示硬盘上的一个文件或目录(实际表示的是一个抽象路径);
-
使用File可以:
-
访问文件或目录属性信息;
-
创建/删除文件或目录;
-
访问目录(注意File不能访问数据)。
-
-
-
绝对路径:
从根目录开始的路径,例如在 Windows 系统中可能是 “C:/Users/Zhang/IdeaProjects/jsd2407/demo.txt”
-
相对路径:
则是相对于当前工作目录的路径。比如,如果当前工作目录是 “C:/Users/Zhang/IdeaProjects/jsd2407”,那么相对路径 “./demo.txt” 。实际开发中使用相对路径;
File常用API
- 实例化文件:
File file = new File(pathname);
找文件夹属性
-
文件名?
file.getName();
-
文件大小?
file.length();
package day15;
import java.io.File;
/**
* - 使用java.io.File有什么用?
* - File的每一个实例用于表示硬盘上的一个文件或目录(实际表示的是一个抽象路径);
* - 使用File可以:
* - 访问文件或目录属性信息;
* - 创建/删除文件或目录;
* - 访问目录(注意File不能访问数据)。
*/
public class FileDemo {
public static void main(String[] args) {
// File file = new File("C:/Users/Zhang/IdeaProjects/jsd2407/demo.txt"); // 绝对路径,应用率不高,因为移动以后就找不到了
// 相对路径中的“./”表示当前目录,在Idea中执行时表示的是当前项目目录,实际开发过程建议使用相对路径!
File file = new File("./demo.txt"); // 创建一个File对象
System.out.println("文件名为:" + file.getName()); // 获取文件名
System.out.println("文件大小为:" + file.length() + "字节"); // 获取文件大小(文件所占用的字节数)
}
}
-
文件是否可读?
fileName.canRead()
-
文件是否可写?
fileName.canWrite()
-
文件是否隐藏?
filaName.isHidden()
package day15;
import java.io.File;
/**
* - 使用java.io.File有什么用?
* - File的每一个实例用于表示硬盘上的一个文件或目录(实际表示的是一个抽象路径);
* - 使用File可以:
* - 访问文件或目录属性信息;
* - 创建/删除文件或目录;
* - 访问目录(注意File不能访问数据)。
*/
public class FileDemo {
public static void main(String[] args) {
// File file = new File("C:/Users/Zhang/IdeaProjects/jsd2407/demo.txt"); // 绝对路径,应用率不高,因为移动以后就找不到了
// 相对路径中的“./”表示当前目录,在Idea中执行时表示的是当前项目目录,实际开发过程建议使用相对路径!
File file = new File("./demo.txt"); // 创建一个File对象
System.out.println("文件名为:" + file.getName()); // 获取文件名
System.out.println("文件大小为:" + file.length() + "字节"); // 获取文件大小(文件所占用的字节数)
System.out.println("是否可读?" + file.canRead()); // 检查文件可读性
System.out.println("是否可写?" + file.canWrite()); // 检查文件可写性
System.out.println("是否隐藏?" + file.isHidden()); // 文件是否隐藏
}
}
文件的创建
-
file.exists()
:判断文件是否存在,返回boolean值; -
file.createNewFile()
:创建文件,会报IOException异常,这里暂时使用Alt+Enter选择第一项抛出该异常;
package day15;
import java.io.File;
import java.io.IOException;
/** 创建文件的演示 */
public class CreateNewFileDemo {
public static void main(String[] args) throws IOException {
// File file = new File("./abc/test.txt");
// 若文件所在的目录不存在,则会在创建时抛出异常
File file = new File("./test.txt");
if (file.exists()) { // 判断File表示的文件或目录是否存在
System.out.println("该文件已存在!");
} else {
file.createNewFile(); // 创建文件,这里报异常,暂时直接抛出
// 光标选中方法后按Alt+回车,选中第一项选择抛出异常
System.out.println("创建成功!");
}
}
}
文件的删除
file.delete()
:删除文件
package day15;
import java.io.File;
/** 删除文件的演示 */
public class DeleteFileDemo {
public static void main(String[] args) {
File file = new File("./test.txt");
if (file.exists()) {
file.delete(); // 删除文件
System.out.println("删除成功!");
} else {
System.out.println("删除失败,文件不存在!");
}
}
}
目录的创建
dir.mkdir()
:创建目录,
package day15;
import java.io.File;
/** 创建目录的演示 */
public class MkDirDemo {
public static void main(String[] args) {
File dir = new File("./demo");
if (dir.exists()) {
System.out.println("目录已存在!创建失败!");
} else {
dir.mkdir(); // 创建目录
System.out.println("目录创建成功!");
}
}
}
- 注意:如果该目录所在的目录不存在,则无法创建,但不会报错!
package day15;
import java.io.File;
/** 创建目录的演示 */
public class MkDirDemo {
public static void main(String[] args) {
File dir = new File("./a/b/c/d");
if (dir.exists()) {
System.out.println("目录已存在!创建失败!");
} else {
dir.mkdir(); // 创建目录
System.out.println("目录创建成功!"); // 创建成功
}
}
}
- 这种情况我们使用
dir.mkdirs()
:如果发现前面的父目录不存在,则该方法会一并创建,实际情况我们常用这种方法创建目录;
package day15;
import java.io.File;
/** 创建目录的演示 */
public class MkDirDemo {
public static void main(String[] args) {
File dir = new File("./a/b/c/d");
if (dir.exists()) {
System.out.println("目录已存在!创建失败!");
} else {
// dir.mkdir(); // 创建目录,但如果父目录不存在,不报错,但是创建失败
dir.mkdirs(); // 创建目录,会将所有不存在的父目录一并创建
System.out.println("目录创建成功!"); // 创建成功
}
}
}
目录的删除
dir.delete()
:删除目录,要求目录必须是空的,所以固然不存在删除父目录同时删除子目录,这种操作被禁止使用;
package day15;
import java.io.File;
/** 删除目录的演示 */
public class DeleteDirDemo {
public static void main(String[] args) {
// File dir = new File("");
File dir = new File("demo");
if (dir.exists()) {
dir.delete(); // 删除目录,要求目录必须是一个空目录,否则将无法删除,但不报错
System.out.println("目录已删除!");
} else {
System.out.println("目录不存在!");
}
}
}
列举子项
-
dir.isDirectory()
:检测指定项是否为目录; -
File[] dir = dir.listFiles()
:列举当前父目录下的所有子项(File)
package day15;
import java.io.File;
/** 访问父目录,列举其中的子项 */
public class ListFilesDemo {
public static void main(String[] args) {
File dir = new File("."); // 当前目录
if (dir.isDirectory()) { // 判断是否为目录
System.out.println("当前目录是一个目录!");
File[] subs = dir.listFiles(); // 获取dir对象表示的目录下的所有子项
for (File sub : subs) {
System.out.println(sub.getName());
}
} else {
System.out.println("当前不是一个目录!失败!");
}
}
}
File[] dir = dir.listFiles(new Filefiter())
:通过重写匿名内部类,带有过滤的列举父目录下所有的子项;
package day15;
import java.io.File;
import java.io.FileFilter;
/** 获取目录的子项,加过滤(条件获取) */
public class ListFilesDemo2 {
public static void main(String[] args) {
File dir = new File("."); // 当前目录
if (dir.isDirectory()) {
File[] files = dir.listFiles(new FileFilter() { // 实例化匿名内部类
@Override
public boolean accept(File file) { // 重写accept方法
// 获取该文件的名称 查看是否以点开头
return file.getName().startsWith("."); // 匹配文件名以点开头的文件
}
});
for (File file : files) { // 遍历文件数组
System.out.println(file.getName()); // 输出文件名
}
} else {
System.out.println("不是目录,无法列举文件名");
}
}
}
使用lambda优化代码
package day15;
import java.io.File;
/** 通过Lambda优化File例子的代码 */
public class LambdaDemo2 {
public static void main(String[] args) {
File dir = new File("."); // 当前目录
if (dir.isDirectory()) { // 判断是否为目录
// 获取当前目录下的"."开头的所有文件
File[] files = dir.listFiles(f -> f.getName().startsWith("."));
for (File f : files) { // 遍历文件
System.out.println(f.getName());
}
} else {
System.out.println("当前目录不是目录!");
}
}
}