1.lambda表达式
概念:
Lambda表达式:特殊的匿名内部类,语法更简洁。
Lambda表达式允许把函数作为一个方法的参数(函数作为方法参数传递),将代码像数据 一样传递。
语法:
<函数式接口> <变量名> = (参数1,参数2...)->{
//方法体
};
代码:
public class My implements Runnable{
@Override
public void run() {
System.out.println("这是自定义任务接口类");
}
}
测试:
public class Test01 {
public static void main(String[] args) {
My m1 = new My();
Thread t1 = new Thread(m1);
t1.start();
//匿名内部类
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("这是匿名内部类方式的任务对象");
}
};
Thread t2 = new Thread(r);
t2.start();
}
}
1.Thread类需要 Runnable接口作为参数,而其中抽象的run 方法是用来指定线程核心任务内容
2. Runnable接口的实现类,重写run方法
3.实现Runnable接口的实现类,使用匿名内部类。
4.必须覆盖重写抽象 run 方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错
//lambda表达式
Runnable r1 = ()->{
System.out.println("这是使用lambda表达式完成的");
};
Thread t3 = new Thread(r1);
t3.start();
1.2无参无返回值
函数式接口:
@FunctionalInterface
interface Swimming {
public void Swimming(String name);
}
测试:
public class Test01 {
public static void main(String[] args) {
//匿名内部类
/*Swimming s = new Swimming() {
@Override
public void Swimming() {
System.out.println("这是使用匿名内部类的方式");
}
};
fun(s);*/
//lambda表达式
Swimming swimming = n-> System.out.println("这是lambda表达式");
fun(n->{
System.out.println("这是lambda表达式 "+n);
});
}
public static void fun(Swimming s){
s.Swimming("张三");
}
}
1.3有参数有返回值的Lambda
public abstract int compare(T o1, T o2);
当需要对一个对象集合进行排序时, Collections.sort 方法需要一个 Comparator 接口实例来指定排序的规则。
public class Person {
private String name;
private int age;
private int height;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", height=" + height +
'}';
}
public Person(String name, int age, int height) {
this.name = name;
this.age = age;
this.height = height;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
public class Test01 {
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
personList.add(new Person("张三",18,188));
personList.add(new Person("李四",23,180));
personList.add(new Person("王五",53,182));
personList.add(new Person("赵六",34,183));
personList.add(new Person("孙琦",32,186));
//对集合中的元素进行排序,按照年龄从小到大。
//传统做法:Comparator:排序规则接口。
Comparator<Person> comparator = (o1, o2)-> o1.getAge()- o2.getAge();
//int:0表示新加的元素和集合中原来的比对的相同
//1:o2比o1小
//-1:o2比o1大
Collections.sort(personList,comparator);
for (Person p:personList){
System.out.println(p);
}
}
}
1.4详细介绍lambda表达式
Lambda引入了新的操作符:->(箭头操作符),->将表达式分为两部分
1.左侧:(参数1,参数2...)表示参数列表
2.右侧:{}内部是方法体
3.如果形参只有一个,()可以省略,只需要参数的名称即可
4.如果执行语句只有一句,且无返回值,{}可以省略,若有返回值,则若想省去{},则必须同时 省略return,且执行语句也保证只有一句
5.Lambda不会生成一个单独的内部类文件
2.函数式接口
1.如果一个接口只有一个抽象方法,称其为函数式接口,函数式接口可以使用Lambda表达式,Lambda表达式,Lambda表达式会被匹配到这个抽象方法上。
2.@Functionallnterface注解检测接口是否符合函数式接口。
内置函数式接口的由来:
interface Operater {
public abstract void getSum(int [] array);
}
public class Test01 {
public static void main(String[] args) {
Operater o = array -> {
int sum = 0;
for (int i : array) {
sum+=i;
}
System.out.println("数组的总和是:"+sum);
};
fun(o);
}
public static void fun(Operater operater){
int [] array = {1,3,5,7,9};
operater.getSum(array);
}
}
常见得函数式接口:
2.1Consumer<T>
有参数,无返回值:
//Consumer<T> 消费性函数式接口
public class Test01 {
public static void main(String[] args) {
Consumer<Double> consumer = t->{
System.out.println("充值了"+t+"话费");
};
fun(consumer,100);
}
//调用某个方法时,该方法需要的参数为接口类型,这时就应该能想到使用lambda
public static void fun(Consumer<Double> consumer,double money){
consumer.accept(money);
}
}
2.2Supplier<T>供给型函数式接口
无参,想有返回结果的函数式接口时:T:表示返回结果的泛型
//Supplier<T> 供给型函数式接口
public class Test02 {
public static void main(String[] args) {
fun(()->new Random().nextInt(10));
}
public static void fun (Supplier<Integer> supplier){
Integer integer = supplier.get();
System.out.println("内容为:"+integer);
}
}
2.3Function<T,R> 函数型函数式接口
T: 参数类型的泛型,R: 函数返回结果的泛型
有参,有返回 值时:
例子: 传入一个字符串把小写转换为大写。
//Function<T,R> 函数型函数式接口
public class Test03 {
public static void main(String[] args) {
fun((t)->{return t.toUpperCase();},"my");
}
public static void fun(Function<String,String> function,String msg){
String apply = function.apply(msg);
System.out.println("内容为:"+apply);
}
}
2.4Predicated<T>
T: 参数的泛型,boolean test(T t);
当传入一个参数时,需要对该参数进行判断时,则需要这种函数:
public class Test05 {
public static void main(String[] args) {
fun((n)->{return n.length()>3?true:false;},"迪丽热巴");
}
public static void fun(Predicate<String> predicate,String name){
boolean test = predicate.test(name);
System.out.println("该名称的长度是否长呀:"+test);
}
}
3.方法引用
3.1lambda表达式的冗余
public class Test06 {
public static void main(String[] args) {
/*fun(array->{int sum=0;
for (Integer i : array) {
sum+=i;
}
System.out.println("数组的长度为:"+sum);
});*/
/*fun(array->Test06.sum(array));*/
fun(Test06::sum);
}
public static void fun(Consumer<Integer[]> consumer){
Integer[] array = {1,3,5,7,9};
consumer.accept(array);
}
public static void sum(Integer[] array){
int sum = 0;
for (Integer i : array) {
sum+=i;
}
System.out.println("数组的和为:"+sum);
}
}
3.2什么是方法引用
方法引用是Lambda表达式的一种简写形式。如果Lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用。
方法引用的分类:
3.3静态方法引用和实例方法引用
public class People {
private String name;
private int age;
public static int compareTo(People p1,People p2){
return p1.getAge()-p2.getAge();
}
public People(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
public class Test01 {
public static void main(String[] args) {
//静态方法的使用
People[] p = {new People("张三",15),new People("李四",18),new People("王五",20)};
//Comparator<People> c = (o1,o2)-> o1.getAge()- o2.getAge();
//Comparator<People> c = (o1,o2)-> People.compareTo(o1,o2);
Comparator<People> c = People::compareTo;
Arrays.sort(p,c);
//实例方法的使用
/*People p = new People("张三",20);
//Supplier<String> s = ()->p.getName();
Supplier<String> s =p::getName;
fun(s);*/
}
public static void fun(Supplier<String> supplier){
String s = supplier.get();
System.out.println("结果为:"+s);
}
}
3.4对象方法引用和构造方法引用
public class People {
private String name;
public People() {
}
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
'}';
}
public People(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Test01 {
public static void main(String[] args) {
//3.对象方法引用: 类名::实例方法. (参数1,参数2)->参数1.实例方法(参数2)
/* Function<String,Integer> function = (str)->{
return str.length();
};*/
Function<String,Integer> function = String::length;
Integer hello = function.apply("hello");
System.out.println(hello);
//比较两个字符串的内容是否一致.T, U, R
// R apply(T t, U u);
/*BiFunction<String,String,Boolean> bi = (t,u)->{
return t.equals(u);
};*/
BiFunction<String,String,Boolean> bi =String::equals;
Boolean apply = bi.apply("hello", "world");
System.out.println(apply);
// 4.构造方法引用: 类名::new (参数)->new 类名(参数)
/*Supplier<String> supplier=()->{
return new String("hello");
};
Supplier<People> supplier=People::new;*/
Function<String,People> function1 = People::new;
People people = function1.apply("张三");
System.out.println(people);
}
}
4.Stream流
Java8的两个重大改变,一个是Lambda表达式,另一个就是本节要讲的Stream API表达式。Stream 是Java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找、过滤、筛选等操作.
4.1为什么使用Stream流
集合操作数据不好的一面,很繁琐。
public class My {
public static void main(String[] args) {
// 一个ArrayList集合中存储有以下数据:张无忌,周芷若,赵敏,张强,张三丰
// 需求:1.拿到所有姓张的 2.拿到名字长度为3个字的 3.打印这些数据
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰");
// 1.拿到所有姓张的
ArrayList<String> zhangList = new ArrayList<>(); // {"张无忌", "张强", "张三丰"}
for (String name : list) {
if (name.startsWith("张")) {
zhangList.add(name);
}
}
// 2.拿到名字长度为3个字的
ArrayList<String> threeList = new ArrayList<>(); // {"张无忌", "张三丰"}
for (String name : zhangList) {
if (name.length() == 3) {
threeList.add(name);
}
}
// 3.打印这些数据
for (String name : threeList) {
System.out.println(name);
}
}
}
Stream流中对于集合的操作语法更加简洁:性能比传统快。
public class Test01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰","赵四");
list.stream()
.filter(item->item.startsWith("张"))
.filter(item->item.length()==3)
.forEach(item-> System.out.println(item));
list.stream()
.filter(i->i.startsWith("赵"))
.filter(i->i.length()==2)
.forEach(System.out::println);
}
}
4.2Stream流的原理
Stream流不是一种数据结构,也不保存数据,而是对数据进行加工处理。Stream可以当做一步一步的流程。在流程上,经过很多个工序使得一个原材料加工成一个商品。
4.3如何获取Stream流对象
public class Test02 {
public static void main(String[] args) {
//实例方法引用:(参数)->对象.实例方法(参数) 对象::实例方法
//item->System.out.println(item); System.out::println
//通过集合对象调用stream()获取流
List<String> list = new ArrayList<>();
list.add("king");
list.add("毛哥");
list.add("家里的");
list.add("已输入");
Stream<String> stream = list.stream();
stream.forEach(System.out::println);
//通过Arrays数组工具类获取Stream对象
int[] i = {1,3,5,7,9};
IntStream stream1 = Arrays.stream(i);
stream1.forEach(System.out::println);
//使用Stream类中of方法
Stream<String> stream2 = Stream.of("张三", "李四", "王五");
stream2.forEach(System.out::println);
//通过IntStream.rangeClosed获取流
IntStream range = IntStream.rangeClosed(1, 5);
range.forEach(System.out::println);
//上面都是获取的串行流。还可以获取并行流。如果流中的数据量足够大,并行流可以加快处速度。
Stream<String> stringStream = list.parallelStream();
stringStream.forEach(System.out::println);
}
}
4.4Stream流中常见的api
中间操作api: 一个操作的中间链,对数据源的数据进行操作。而这种操作的返回类型还是一个Stream对象,只有有了终止操作,才会执行中间链,产生其结果。
终止操作api: 一个终止操作,执行中间操作链,并产生结果,使得中间链的返回类型不再是Stream流对象。
public class Test03 {
public static void main(String[] args) {
List<People> personList = new ArrayList<>();
personList.add(new People("欧阳雪",18,"中国",'F'));
personList.add(new People("Tom",24,"美国",'M'));
personList.add(new People("Harley",22,"英国",'F'));
personList.add(new People("向天笑",20,"中国",'M'));
personList.add(new People("李康",22,"中国",'M'));
personList.add(new People("小梅",20,"中国",'F'));
personList.add(new People("何雪",21,"中国",'F'));
personList.add(new People("李康",22,"中国",'M'));
//findFirst allMatch所有的都符合才返回true否则返回false anyMatch有一个符合就为true noneMatch没有一个符合就返回true parallel转为并行流
/*Optional<People> first = personList.parallelStream()
.filter(i -> i.getSex() == 'F')
.findFirst();*/
boolean l = personList.parallelStream()
.filter(i -> i.getSex() == 'F')
.allMatch(i -> i.getAge() > 15);
System.out.println(l);
//搜集方法 collect 它属于终止方法
//年龄大于20且性别为M
List<People> collect = personList.stream()
.filter(i -> i.getAge() > 20)
.filter(i -> i.getSex() == 'M')
.collect(Collectors.toList());
System.out.println(collect);
//求集合中所有人的年龄和,参数和返回类型必须一致
Optional<Integer> reduce = personList.stream()
.map(i -> i.getAge())
.reduce((a, b) -> a + b);
System.out.println(reduce.get());
//查找最大年龄的人
Optional<People> max = personList.stream()
.max((o1, o2) -> o1.getAge() - o2.getAge());
System.out.println(max.get());
//查找年龄最小的人
Optional<People> min = personList.stream()
.min((o1, o2) -> o1.getAge() - o2.getAge());
System.out.println(min.get());
//对流中元素排序
personList.stream()
.sorted((o1,o2)->o1.getAge()-o2.getAge())
.forEach(System.out::println);
//集合中所有元素的名字和年龄
personList.stream()
.map(i->{
Map<String,Object> m = new HashMap<>();
m.put("name",i.getName());
m.put("age",i.getAge());
return m;})
.forEach(System.out::println);
//找到年龄大于20岁的人并输出;filter()过滤器需要一个断言接口函数,断言接口返回true,获取该元素。foreach(Consumer)
personList.stream()
.filter(i->i.getAge()>20)
.forEach(System.out::println);
//找出所有中国人的数量 count
long o = personList.stream()
.filter(i -> i.getCountry().equals("中国"))
.count();
System.out.println(o);
}
}
5.新增了日期时间类
LocalDate: 表示日期类。yyyy-MM-dd
LocalTime: 表示时间类。 HH:mm:ss
LocalDateTime: 表示日期时间类 yyyy-MM-dd t HH:mm:ss zzz
DatetimeFormatter:日期时间格式转换类。
Instant: 时间戳类。
Duration: 用于计算两个日期类
public class Test01 {
public static void main(String[] args) {
//LocalDate: 表示日期类。yyyy-MM-dd
//LocalTime: 表示时间类。 HH:mm:ss
//LocalDateTime: 表示日期时间类 yyyy-MM-dd t HH:mm:ss.zzz
//DatetimeFormatter:日期时间格式转换类。
//Instant: 时间戳类。
//Duration: 用于计算两个日期类
LocalDate now = LocalDate.now();//获取当前日期
LocalDate of = LocalDate.of(2022, 7, 20);//自己指定日期
System.out.println(now);
System.out.println(of);
LocalTime now1 = LocalTime.now();//获取当前时间
LocalTime of1 = LocalTime.of(21, 32, 56, 60000000);//自己指定时间
System.out.println(now1);
System.out.println(of1);
LocalDateTime now2 = LocalDateTime.now();//获取当前日期时间
LocalDateTime of2 = LocalDateTime.of(2022, 6, 20, 21, 34,20);//自己指定日期时间
//计算两个日期相差的天数
Duration between = Duration.between(of2, now2);
System.out.println(between.toDays());
System.out.println(now2);
System.out.println(of2);
//把字符串转为日期格式
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate parse = LocalDate.parse("2022-07-20", dateTimeFormatter);
//把时间格式转为字符串
String format = parse.format(dateTimeFormatter);
System.out.println(format);
System.out.println(parse);
}
}