第一章 Lambda表达式
1.1 Lambda格式:
标准格式:
(参数类型 参数名称) -> {代码语句}
格式说明:
小括号内的语法与传统方法参数列表一致: 无参数则留空; 多个参数用逗号分隔
-> 是新引入的语法格式, 代表指向动作;
大括号内的语法与传统方法体要求基本一致;
匿名内部类与Iambda对比:
new Thread(new Runnable(){
@Override
Public void run(){
System.out.println("多线程任务执行!");
}
}).start();
() -> System.out.println("多线程任务执行!");
Lambda表达式理解为 对某一个接口中的抽象方法的 匿名重写
前提:
1. 一定是接口
2. 接口中有且只有一个抽象方法
省略格式:
可推导的就是可省略的
1. 参数类型可以省略
2. 如果只有一个参数 ()可以省略
3. 如果方法体只有一句话 return 大括号 ; 都可以省略
但必须是同时省略
第二章 函数式接口
2.1 概述
函数式接口在java中是指:有且仅有一个抽象方法的接口
格式:
只要确保接口中有且仅有一个抽象方法即可:
修饰符 interface 接口名称{
public abstract 返回值类型 方法名称(可选参数信息);
//其他非抽象方法内容
}
2.2 常用函数式接口
2.2.1 Supplier接口
java.util.function.Supplier<T>接口, 它意味着"供给" , 对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据。
抽象方法 : T get();
代码演示(求数组元素最大值):
public static void main(String[] args) {
int[] arr = {3,8,2,5,0};
method(()->{
//给数组进行自然排序(即由小到达进行排序)
Arrays.sort(arr);
//返回最大索引对应的值 即最大值
return arr[arr.length-1];
});
}
public static void method(Supplier<Integer> s){
Integer max = s.get();
System.out.println(max);
}
2.2.2 Consumer接口
java.util.function.Consumer<T>接口则正好相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型参数决定
抽象方法:
void accept(T t);
默认方法:
andThen()
代码演示(使用Consumer接口作为方法的参数将一个字符串转换大小写并打印):
public static void main(String[] args) {
//标准格式
method("Hello world",(String s)->{
System.out.println(s.toUpperCase());
},(String s)->{
System.out.println(s.toLowerCase());
});
//省略格式
method("Hello World",s-> System.out.println(s.toLowerCase()),s-> System.out.println(s.toUpperCase()));
}
public static void method(String s, Consumer<String> c1, Consumer<String> c2){
c1.accept(s);
c2.accept(s);
// c1.andThen(c2).accept(s);
}
2.2.3 Function接口
java.util.function.Function<T,R>:接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。有进有出,所以称为“函数Function”。
抽象方法:
R apply(T t)
Function接口中最主要的抽象方法为:R apply(T t),根据类型T的参数获取类型R的结果。
使用的场景例如:将String类型转换为Integer类型。
代码演示:
public static void main(String[] args) {
//标准格式
method("100",(String s)->{
return Integer.parseInt(s);
});
//省略格式
method("1000",s->Integer.parseInt(s));
/*
方法引用
前提 Lambda表达式只有一句话 可能使用
类名引用静态方法:
类名::方法名
*/
method("10000",Integer::parseInt);
}
public static void method(String num, Function<String, Integer> f){
Integer n = f.apply(num);
System.out.println(n);
}
代码演示(类名引用构造方法):
public class Person {
private String name;
public Person() {}
public Person(String name) {this.name = name;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
public static void main(String[] args) {
//标准格式
method("柳岩",(String name)->{
return new Person(name);
});
//省略格式
method("唐嫣",name->new Person(name));
/*
类名引用构造方法
类名::new
*/
method("金莲",Person::new ); //类名引用带参构造
System.out.println("-----------------------------------");
method2(Person::new); //类名引用空参构造
}
public static void method(String name, Function<String, Person> f){
Person p = f.apply(name);
System.out.println(p);
}
public static void method2(Supplier<Person> s){
Person p = s.get();
System.out.println(p);
}
2.2.4 Predicate接口
有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用java.util.function.Predicate<T>接口。
抽象方法:
boolean test(T t) 用于条件判断的场景
默认方法:
Predicate and(Predicate p) 并且
Predicate or(Predicate p) 或者
Predicate nagete() 取反
代码演示(判断字符串是否以 .java 结尾):
public static void main(String[] args) {
//标准格式
method("HelloWorld.java",(String name)->{
return name.toLowerCase().endsWith(".java");
});
//省略格式
method("Hello World.java",s -> s.toLowerCase().endsWith(".java"));
}
public static void method(String fileName, Predicate<String> p ){
boolean test = p.test(fileName);
System.out.println(test);
}
//判断字符串是否包含H W
public static void main(String[] args) {
//标准格式
method1("Hello World", (String s) -> {
return s.contains("H");
}, (String s) -> {
return s.contains("W");
});
//省略格式
method1("Hello World", s -> s.contains("H"), s -> s.contains("W"));
}
public static void method1(String s, Predicate<String> p1, Predicate<String> p2) {
// boolean b1 = p1.test(s);
// boolean b2 = p2.test(s);
// if (b1 && b2) {
// System.out.println("既包含H又包含W");
// }
boolean b = p1.and(p2).test(s);
if (b){
System.out.println("既包含H又包含W");
}
}
第四章 Stream流
4.1 获取流方式
java.util.stream.Stream接口
获取Stream流对象
1. Collection接口
Public default Stream stream()
2. Stream接口静态方法
static Stream of(T...t);
4.2 常用方法
终结方法(只能调用一次): 返回值类型不再是 Stream 接口自身类型的方法,因此不再支持类似`StringBuilder`那样的链式调用。
本小节中,终结方法包括 count 和 forEach 方法
long count(); 统计个数
void forEach(Consumer action); 逐一处理
非终结方法: 返回值类型仍然是`Stream`接口自身类型的方法,因此支持链式调用
Stream<T> limit(long maxSize):获取Stream流对象中的前n个元素,返回一个新的Stream流对象
Stream<T> skip(long n): 跳过Stream流对象中的前n个元素,返回一个新的Stream流对象
Stream<T> distinct(); 去重
Stream<T> filter(Predicate<? super T> predicate); 过滤 可以通过`filter`方法将一个流转换成另一个子集流
<R> Stream<R> map(Function<? super T, ? extends R> mapper); 映射 该接口需要一个 Function函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的流。
静态方法:
Stream concat(Stream s1, Stream s2) 组合(将两个流合并成一个新的流)
代码演示:
public static void main(String[] args) {
Stream<String> stream = Stream.of("大娃","二娃","三娃","四娃","五娃","六娃","七娃","爷爷","蛇精","蝎子精","蛇精","蝎子精");
//统计个数
long count = stream.count();
System.out.println(count);
//逐一处理(类似于遍历)
stream.forEach(System.out::println);
//获取前8个 跳过前7个 将第8个单独输出
stream.limit(8).skip(7).forEach(System.out::println);
//跳过前7个, 获取剩余的第一个元素 再将元素输出
stream.skip(7).limit(1).forEach(System.out::println);
//去重
stream.distinct().forEach(System.out::println);
//过滤 筛选
stream.filter(s->s.contains("精")).forEach(System.out::println);
//映射 将一种类型转换成另一种类型
Stream<Person> personStream = stream.map(Person::new);
personStream.forEach(System.out::println);
//组合 拼接
Stream<String> s2 = Stream.of("1", "2", "3");
Stream.concat(stream,s2).forEach(System.out::println);
}
Stream综合案例
现在有两个`ArrayList`集合存储队伍当中的多个成员姓名,要求使用传统的Stream流方式,进行以下若干操作步骤:
1. 第一个队伍只要名字为3个字的成员姓名;
2. 第一个队伍筛选之后只要前3个人;
3. 第二个队伍只要姓张的成员姓名;
4. 第二个队伍筛选之后不要前2个人;
5. 将两个队伍合并为一个队伍;
6. 打印整个队伍的姓名信息。
代码演示:
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class lianXi {
public static void main(String[] args) {
List<String> one = new ArrayList<>();
one.add("迪丽热巴");
one.add("宋远桥");
one.add("苏星河");
one.add("老子");
one.add("庄子");
one.add("孙子");
one.add("洪七公");
List<String> two = new ArrayList<>();
two.add("古力娜扎");
two.add("张无忌");
two.add("张三丰");
two.add("赵丽颖");
two.add("张二狗");
two.add("张天爱");
two.add("张三");
// 1. 第一个队伍只要名字为3个字的成员姓名;
Stream<String> stream = one.stream().filter(s -> s.length() == 3);
// 2. 第一个队伍筛选之后只要前3个人;
// 3. 第二个队伍只要姓张的成员姓名;
//two.stream().filter(s->s.startsWith("张")).forEach(System.out::println);
// 4. 第二个队伍筛选之后不要前2个人;
Stream<String> to2 = two.stream().filter(s -> s.startsWith("张")).skip(2);
// 5. 将两个队伍合并为一个队伍;
// 6. 打印整个队伍的姓名信息。
Stream.concat(stream, to2).forEach(System.out::println);
}
}
结果:
宋远桥
苏星河
洪七公
张二狗
张天爱
张三