1、Lambda表达式
1、函数式接口
接口中只有一个必须实现的抽象方法。
@FunctionalInterface
interface Calculator {
// 方法是有参数也有返回值
public abstract int calc(int a, int b);
}
@FunctionalInterface
interface Inter{
public abstract void show1();
// 注意 : Object类中方法作为抽象方法, 那么子类是可以不重写!!
public abstract boolean equals(Object obj);
}
注意:
- 只有一个抽象方法需要重写的接口,函数式接口。函数式接口是允许有其他的非抽象方法的存在例如静态方法,默认方法,私有方法。
- 为了标识接口是一个函数式接口,可以在接口之上加上一个注解: @FunctionalInterface 以示区别
- 在JDK中 java.util.function 包中的所有接口都是函数式接口。我们之前学习线程时学习的Runnable也是函数式接口
2、lambda表达式的使用(匿名实现类对象的简写)
1、使用前提(函数式接口)
- 必须存在一个接口
- 接口中有且只有一个必须实现的抽象方法
2、使用格式
(参数列表)->{代码块}
- 形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
- ->:由英文中画线和大于符号组成,固定写法。代表指向动作
- 代码块:是我们具体要做的事情,也就是以前我们写的方法体内容
public class LambdaTest1 {
public static void main(String[] args) {
useShowHandler(() -> {
System.out.println("我是一个lambda表达式....");
});
}
public static void useShowHandler(ShowHandler showHandler) {
showHandler.show();
}
}
interface ShowHandler {
public abstract void show();
}
3、省略规则
- 小括号内参数的类型可以省略;
- 如果小括号内有且仅有一个参,则小括号可以省略;
- 如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。
2、方法引用
方法引用是为了进一步简化Lambda表达式的写法。
方法引用的格式:类型或者对象::引用的方法。
目标:方法引用有四种形式:
1.静态方法的引用。
2.实例方法的引用。
3.特定类型方法的引用。
4.构造器引用。
1、.静态方法的引用
当出现了这种形式,则可以使用
// 如果前后参数是一样的,而且方法是静态方法,既可以使用静态方法引用
Collections.sort(lists, ( o1, o2) -> Student.compareByAge(o1 , o2));
||
||
V
Collections.sort(lists, Student::compareByAge);
实例:
public class MethodDemo01 {
public static void main(String[] args) {
List<Student> lists = new ArrayList<>();
Student s1 = new Student("李铭",18,'男');
Student s2 = new Student("冯龙",23,'男');
Student s3 = new Student("王乐乐",21,'男');
Collections.addAll(lists , s1 , s2 , s3);
System.out.println(lists);
Collections.sort(lists, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
});
// Lambda表达式简化参数二:匿名内部类的Comparator写法!
Collections.sort(lists, (Student o1, Student o2) -> {
return o1.getAge() - o2.getAge();
});
Collections.sort(lists, (Student o1, Student o2) -> o1.getAge() - o2.getAge());
Collections.sort(lists, ( o1, o2) -> o1.getAge() - o2.getAge());
// 使用静态方法进行简化!
Collections.sort(lists, ( o1, o2) -> Student.compareByAge(o1 , o2));
// 如果前后参数是一样的,而且方法是静态方法,既可以使用静态方法引用
Collections.sort(lists, Student::compareByAge);
System.out.println(lists);
}
}
2、实例方法的引用(与静态引用差不多)
当出现了这种形式,则可以使用
// 如果前后参数是一样的,而且方法是实例方法,既可以使用静态方法引用
lists.forEach(s -> System.out.println(s));
||
||
v
lists.forEach(System.out::println);
实例:
public class MethodDemo01 {
public static void main(String[] args) {
List<String> lists = new ArrayList<>();
lists.add("java1");
lists.add("java2");
lists.add("java3");
// 对象是 System.out = new PrintStream();
// 实例方法:println()
// 前后参数正好都是一个
lists.forEach(s -> System.out.println(s));
lists.forEach(System.out::println);
}
}
3、特定类型方法的引用。
特定类型:String ,任何类型。
格式:特定类型::方法。
注意:
如果第一个参数列表中的形参中的第一个参数作为了后面的方法的调用者,
并且其余参数作为后面方法的形参,那么就可以用特定类型方法引用了。
Arrays.sort(strs, ( s1, s2 ) -> s1.compareToIgnoreCase(s2));
// 如果第一个参数列表中的形参中的第一个参数作为了后面的方法的调用者,
// 并且其余参数作为后面方法的形参,那么就可以用特定类型方法引用了。
// 特定类型的方法引用:
Arrays.sort(strs, String::compareToIgnoreCase);
实例:
public class MethodDemo01 {
public static void main(String[] args) {
String[] strs = new String[]{"James", "AA", "John",
"Patricia","Dlei" , "Robert","Boom", "Cao" ,"black" ,
"Michael", "Linda","cao","after","sBBB"};
// public static <T> void sort(T[] a, Comparator<? super T> c)
// 需求:按照元素的首字符(忽略大小写)升序排序!!!
Arrays.sort(strs, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareToIgnoreCase(s2);// 按照元素的首字符(忽略大小写)比较。
}
});
Arrays.sort(strs, (String s1, String s2) -> {
return s1.compareToIgnoreCase(s2);// 按照元素的首字符(忽略大小写)比较。
});
Arrays.sort(strs, ( s1, s2 ) -> s1.compareToIgnoreCase(s2));
// 特定类型的方法引用:
Arrays.sort(strs, String::compareToIgnoreCase);
System.out.println(Arrays.toString(strs));
}
}
4、构造器引用。
格式是:类名::new。
注意点:前后参数一致的情况下,又在创建对象就可以使用构造器引用
String[] strs1 = lists.toArray(s -> new String[s] );
String[] strs2 = lists.toArray(String[]::new);
3、Stream流(一般使用在数组,集合上,对元素进行筛选,加工等操作)java.util.stream
流式思想:这张图中展示了过滤、映射、跳过、计数等多步操作,这是一种集合元素的处理方案,而方案就是一种“函数模型”。图中的每一个方框都是一个“流”,调用指定的方法,可以从一个流模型转换为另一个流模型。而最右侧的数字3是最终结果。
1、获取流方式
1、获取Collection流(default Stream stream())
Collection接口的默认方法:default Stream stream();
Collection<String> c = new ArrayList<>();
Stream<String> ss = c.stream();
2、获取Map流
不可获取map集合整体的流,可以获取map结合的keyset流,values流,entryset流
Map<String, Integer> map = new HashMap<>();
// 先获取键的Stream流。
Stream<String> keyss = map.keySet().stream();
// 在获取值的Stream流
Stream<Integer> valuess = map.values().stream();
// 获取键值对的Stream流(key=value: Map.Entry<String,Integer>)
Stream<Map.Entry<String,Integer>> keyAndValues = map.entrySet().stream();
3、获取数组流( Arrays.stream() , Stream.of() )
String[] arrs = new String[]{"Java", "JavaEE" ,"Spring Boot"};
Stream<String> arrsSS1 = Arrays.stream(arrs);
Stream<String> arrsSS2 = Stream.of(arrs);
4、获取 同种类型可变长度 的 参数流( Stream.of(T… t1,t2,t2) )
Stream<String> stream = Stream.of("张三","李四","王五","赵六");
2、流方法
1、获取方法
1 单列集合
可以使用Collection接口中的默认方法stream()生成流
default Stream<E> stream()
2 双列集合
双列集合不能直接获取 , 需要间接的生成流
可以先通过keySet或者entrySet获取一个Set集合,再获取Stream流
3 数组
Arrays中的静态方法stream生成流
Arrays.stream( arr ) ,Stream.of( arr )
4 可变参数
Stream.of( T... t1,t2,t3…… )
2、中间方法
1 Stream<T> filter(Predicate predicate):用于对流中的数据进行过滤
Predicate接口中的方法 : boolean test(T t):对给定的参数进行判断,返回一个布尔值
2 Stream<T> limit(long maxSize):截取指定参数个数的数据
3 Stream<T> skip(long n):跳过指定参数个数的数据
4 static <T> Stream<T> concat(Stream a, Stream b):合并a和b两个流为一个流
5 Stream<T> distinct():去除流中重复的元素。依赖(hashCode和equals方法)
6 Stream<T> sorted () : 将流中元素按照自然排序的规则排序
7 Stream<T> sorted (Comparator<? super T> comparator) : 将流中元素按照自定义比较器规则排序
8 <R> Stream<R> map(Function<? super T, ? extends R> mapper); 对元素进行加工,比如将所有元素类型 int-->Integer
import java.util.stream.Stream;
public class Demo08StreamMap {
public static void main(String[] args) {
Stream<String> original = Stream.of("10", "12", "18");
Stream<Integer> result = original.map(s->Integer.parseInt(s));
}
}
public class DemoStreamNames {
public static void main(String[] args) {
List<String> one = new ArrayList<>();
// ...
List<String> two = new ArrayList<>();
// ...
// 第一个队伍只要名字为3个字的成员姓名;
// 第一个队伍筛选之后只要前3个人;
Stream<String> streamOne = one.stream().filter(s -> s.length() == 3).limit(3);
// 第二个队伍只要姓张的成员姓名;
// 第二个队伍筛选之后不要前2个人;
Stream<String> streamTwo = two.stream().filter(s -> s.startsWith("张")).skip(2);
// 将两个队伍合并为一个队伍;
// 根据姓名创建Person对象;
// 打印整个队伍的Person对象信息。
Stream.concat(streamOne, streamTwo).map(s-> new Person(s)).forEach(s->System.out.println(s));
}
}
3、终结方法
Stream流中三类方法之一 : 终结方法
1 void forEach(Consumer action):对此流的每个元素执行操作
Consumer接口中的方法 void accept(T t):对给定的参数执行此操作
2 long count():返回此流中的元素数
3、流的收集
R collect(Collector collector) : 此方法只负责收集流中的数据 , 创建集合添加数据动作需要依赖于参数
public static <T> Collector toList():把元素收集到List集合中
public static <T> Collector toSet():把元素收集到Set集合中
public static Collector toMap(Function keyMapper,Function valueMapper):把元素收集到Map集合中
Object[] toArray();收集到数组
public class Demo15StreamCollect {
public static void main(String[] args) {
Stream<String> stream = Stream.of("10", "20", "30", "40", "50");
List<String> list = stream.collect(Collectors.toList());
Set<String> set = stream.collect(Collectors.toSet());
Object[] objArray = stream.toArray();
}
}
Map<String, String> collect = list.stream().collect(Collectors.toMap(
(s) -> s.split("\\.")[1].split("-")[0],//key值
(s) -> s.split("-字")[1])//value值
);
4、File类
java.io.File
类是文件和目录路径名的抽象表示。
1、构造器
public File(String pathname)
:通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。public File(String parent, String child)
:从父路径名字符串和子路径名字符串创建新的 File实例。public File(File parent, String child)
:从父抽象路径名和子路径名字符串创建新的 File实例。
注意:
- 一个File对象代表硬盘中实际存在的一个文件或者目录。
- 无论该路径下是否存在文件或者目录,都不影响File对象的创建。
2、方法
1、创建与删除
- `public boolean createNewFile()` :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。 (目录必须存在)
- `public boolean delete()` :删除由此File表示的文件或目录。
(如果删除的是一个文件夹,需要先删除文件夹中的内容,最后才能删除文件夹)
- `public boolean mkdir()` :创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。
- `public boolean mkdirs()` ::创建文件目录。如果上层文件目录不存在,一并创建。(创建多级目录)
2、获取文件相关的特性
public boolean isDirectory() 测试此抽象路径名表示的File是否为目录
public boolean isFile() 测试此抽象路径名表示的File是否为文件
public boolean exists() 测试此抽象路径名表示的File是否存在
public String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串
public String getPath() 将此抽象路径名转换为路径名字符串(返回值是File类创建时在构造器填入的 字符串 )
public String getName() 返回由此抽象路径名表示的文件或目录的名称
public long length() :返回由此File表示的文件的长度。
public long lastModified() :获取最后一次的修改时间,毫秒值
public boolean canRead() :判断是否可读
public boolean canWrite() :判断是否可写
public boolean isHidden() :判断是否隐藏
public boolean renameTo(File dest):把文件重命名为指定的文件路径
-
绝对路径:从盘符开始的路径,这是一个完整的路径。
-
相对路径:在idea中相对于project目录的路径,
-
默认的当前路径在系统属性user.dir中存储
-
String root = System.getProperty("user.dir");//默认相对路径 String filePath = root+File.separator+"P1"+File.separator+"txt"+ File.separator +fileName;
-
-
路径分隔符
-
windows和DOS系统默认使用“\”来表示 UNIX和URL使用“/”来表示 File类提供了一个常量: public static final String separator。根据操作系统,动态的提供分隔符。
-
3、目录的遍历
-
public String[] list()
:返回一个String数组,表示该File目录中的所有子文件或目录。 -
public File[] listFiles()
:返回一个File数组,表示该File目录中的所有的子文件或目录。-
1 当调用者不存在时,返回null 2 当调用者是一个文件时,返回null 3 当调用者是一个空文件夹时,返回一个长度为0的数组 4 当调用者是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回 5 当调用者是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏内容
-
//递归删除一个文件夹中所有功能
public static void removeFile(File dir){
File[] files = dir.listFiles();
if(files==null)
{
return;
}
for(File file:files)
{
if(file.isFile())
{
file.delete();
}
if(file.isDirectory())
{
removeFile(file);
}
}
dir.delete();
}
//递归删除一个文件夹中所有功能
public static void removeFile(File dir){
File[] files = dir.listFiles();
if(files==null)
{
return;
}
for(File file:files)
{
if(file.isFile())
{
file.delete();
}
if(file.isDirectory())
{
removeFile(file);
}
}
dir.delete();
}