1. lambda表达式
概念:
Lambda表达式:特殊的匿名内部类,语法更简洁。
Lambda表达式允许把函数作为一个方法的参数(函数作为方法参数传递),将代码像数据一样传递。
语法:
<函数式接口> <变量名> = (参数1,参数2...) -> {
//方法体
};
注意:函数式接口:如果一个接口只有一个抽象方法,则该接口称之为函数式接口。
(参数1,参数2):抽象方法的参数,形参列表的数据类型会自动推断;如果形参列表为空,只需要保留();如果形参只有1个,()可以省略,只需要参数的名称即可。
-> : 分隔符,Lambda引入了新的操作符。
{} : 表示抽象方法的实现(方法体),如果执行语句只有一句,且无返回值,{}可以省略;若有返回值,则若想省去{},则必须同时省略return,且执行语句也保证只有一句。
package demo01;
public class Test01 {
public static void main(String[] args) {
Runnable runnable = () ->{
System.out.println("这是lambda表达式方式创建的任务方法对象");
};
Thread t1 = new Thread(runnable);
t1.start();
}
}
Lambda表达式的作用:简化匿名内部类的使用,语法更加简单。
2. 函数式接口
如果一个接口只有一个抽象方法,则该接口称之为函数式接口,函数式接口可以使用Lambda表达式,Lambda表达式会被匹配到这个抽象方法上。
@FunctionalInterface 注解检测接口是否符合函数式接口。
常见的函数式接口
由于Lambda使用时不关心接口名,抽象方法名,只关心抽象方法的参数列表和返回值类型。因此JDK提供了大量常用的函数式接口。java.util.function
2.1 Consumer<T>
有参数,无返回值。
package demo03;
import java.util.function.Consumer;
public class Test03 {
public static void main(String[] args) {
fun(arr -> {
int sum=0;
for(int n:arr){
sum+=n;
}
System.out.println("数组的和为:"+sum);
});
}
public static void fun(Consumer<int[]> consumer){
int[] arr={1,3,5,7,8,10};
consumer.accept(arr);
}
}
2.2 Supplier<T>供给型函数式接口
T:表示返回结果的泛型 无参,有返回结果的函数式接口时。
package demo04;
import java.util.Random;
import java.util.function.Supplier;
public class Test04 {
public static void main(String[] args) {
fun(()->{
return new Random().nextInt(10);
});
}
public static void fun(Supplier<Integer> supplier){
Integer integer = supplier.get();
System.out.println("内容:"+integer);
}
}
2.3 Function<T,R> 函数型函数式接口
T:参数类型的泛型
R:函数返回结果的泛型
有参,有返回值时。
package demo05;
import java.util.function.Function;
public class Test05 {
public static void main(String[] args) {
fun((t)->{
return t.toUpperCase();
},"hello world");
}
public static void fun(Function<String,String> function,String msg){
String s = function.apply(msg);
System.out.println("字符串小写转大写后:"+s);
}
}
2.4 Predicated<T>
T: 参数的泛型 返回一个boolean值
当传入一个参数时,需要对该参数进行判断时,则需要这种函数。
package demo06;
import java.util.function.Predicate;
public class Test06 {
public static void main(String[] args) {
fun((t)->{
return t.length()>2?true:false;
},"小黄人");
}
public static void fun(Predicate<String> predicate,String name){
boolean test = predicate.test(name);
System.out.println("名字长度是否大于2:"+test);
}
}
3. 方法引用
如果我们在Lambda中所指定的功能,已经有其他方法存在相同方案,没必要再写重复的逻辑,可以直接"引用"过去。
package demo07;
import java.util.function.Consumer;
public class Test07 {
public static void main(String[] args) {
fun(Test07::sum);
}
public static void fun(Consumer<int[]> consumer){
int[] arr={1,2,3,4,5};
consumer.accept(arr);
}
public static void sum(int[] arr){
int sum=0;
for(int n:arr){
sum+=n;
}
System.out.println("数组的和为:"+sum);
}
}
方法引用是Lambda表达式的一种简写形式,如果Lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用。
常见形式:
对象::实例方法
类::静态方法
类::实例方法
类::new
请注意其中的双冒号 :: 写法,这被称为"方法引用",是一种新的语法。
方法引用的分类:
3.1 静态方法引用
对应的Lambda表达式: (args)->类名.staticMethod(args)
package demo07;
import java.util.function.Consumer;
public class Test07 {
public static void main(String[] args) {
// fun((arr)->Test07.sum(arr));
fun(Test07::sum);
}
public static void fun(Consumer<int[]> consumer){
int[] arr={1,2,3,4,5};
consumer.accept(arr);
}
public static void sum(int[] arr){
int sum=0;
for(int n:arr){
sum+=n;
}
System.out.println("数组的和为:"+sum);
}
}
3.2 实例方法引用
对应的Lambda表达式: (args)->inst.instMethod(args)
package demo08;
import java.util.function.Supplier;
public class Test08 {
public static void main(String[] args) {
User user = new User("暧昧",18);
//Supplier<String> supplier = ()->user.getName();
Supplier<String> supplier = user::getName;
System.out.println(supplier.get());
}
}
class User{
private String name;
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.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;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
3.3 对象方法引用
对应的Lambda表达式: (inst,args)->inst.instMethod(args)
package demo09;
import java.util.function.BiFunction;
public class Test09 {
public static void main(String[] args) {
// BiFunction<String,String,Boolean> biFunction = (x,y)->x.equals(y);
BiFunction<String,String,Boolean> biFunction = String::equals;
Boolean apply = biFunction.apply("hello", "world");
System.out.println(apply);
}
}
3.4 构造方法引用
对应的Lambda表达式: (args)->new 类名(args)
package demo10;
import java.util.function.Function;
public class Test10 {
public static void main(String[] args) {
// Function<String,String> function = (x)->new String(x);
Function<String,String> function = String::new;
String hello = function.apply("hello");
System.out.println(hello);
}
}
4. Stream流
Stream 是Java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找、过滤、筛选等操作.
4.1 Stream流的原理
Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工 处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。
4.2 如何获取Stream流对象
package demo12;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class Test12 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("暧昧");
list.add("小黄人");
list.add("大yelou");
Stream<String> stream = list.stream();
Integer[] arr = {1,5,8,10,15};
Stream<Integer> stream1 = Arrays.stream(arr);
Stream<String> stream2 = Stream.of("张三", "李四", "王五", "刘六");
IntStream stream3 = IntStream.of(1, 2, 3, 5, 6);
//上面都是串行流,这个是并行流。如果流中的数据量足够大,并行流可以加快速度。
Stream<String> stringStream = list.parallelStream();
}
}
4.3 Stream流中常见的api
中间操作api:一个操作的中间链,对数据源的数据进行操作。而这种操作的返回类型还是一个Stream对象。
终止操作api:一个终止操作,执行中间操作链,并产生结果,返回类型不在是Stream流对象。
package demo13;
import java.util.*;
import java.util.stream.Collectors;
public class Test13 {
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪",18,"中国",'F'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("Harley",22,"英国",'F'));
personList.add(new Person("向天笑",20,"中国",'M'));
personList.add(new Person("李康",22,"中国",'M'));
personList.add(new Person("小梅",20,"中国",'F'));
personList.add(new Person("何雪",21,"中国",'F'));
personList.add(new Person("李康",22,"中国",'M'));
//输出country为英国的元素
//personList.stream().filter(item -> item.getCountry().equals("英国")).forEach(System.out::println);
//输出sex为F的元素
//personList.stream().filter(item->item.getSex()=='F').forEach(System.out::println);
//只要name 和 age , 原来流中每个元素转换成另一种格式。
// map--接收Lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
// personList.stream().map(item->{
// Map<String,Object> map = new HashMap<>();
// map.put("name",item.getName());
// map.put("age",item.getAge());
// return map;
// }).forEach(System.out::println);
//根据年龄排序
//personList.stream().sorted((o1,o2)->o1.getAge()-o2.getAge()).forEach(System.out::println);
//输出年龄最大的
//Optional<Person> max = personList.stream().max((o1, o2) -> o1.getAge() - o2.getAge());
//System.out.println(max.get());
//输出年龄最小的
//Optional<Person> min = personList.stream().min((o1, o2) -> o1.getAge() - o2.getAge());
//System.out.println(min);
//规约reduce
//求集合中所有人的年龄和
//Optional<Integer> reduce = personList.stream().map(item -> item.getAge()).reduce((a, b) -> a + b);
//System.out.println(reduce.get());
//求a有初始化值的规约
//Integer reduce = personList.stream().map(item -> item.getAge()).reduce(20, (a, b) -> a + b);
//System.out.println(reduce);
//collect搜集 搜集年龄大于20且性别为F的
//List<Person> collect = personList.stream().filter(item -> item.getAge() > 20).filter(item -> item.getSex() == 'F').collect(Collectors.toList());
//findFirst() 方法根据命名可以大致知道是获取Optional流中的第一个元素。
//findAny() 方法是获取Optional 流中任意一个,存在随机性,其实里面也是获取元素中的第一个。(适用于并行流)
//Optional<Person> first = personList.stream().filter(item -> item.getSex() == 'F').findFirst();
//System.out.println(first.get());
//allMatch 查询所有元素都符合条件则返回true
//boolean b = personList.stream().allMatch(item -> item.getAge() > 17);
//System.out.println(b);
//anyMatch 查询任一元素有一个符合条件则返回true
//boolean b = personList.stream().anyMatch(item -> item.getAge() > 23);
//System.out.println(b);
//noneMatch 查询没有一个元素符合我们的条件则返回true
//boolean b = personList.stream().noneMatch(item -> item.getAge() > 23);
//System.out.println(b);
}
}
class Person {
private String name;
private Integer age;
private String country;
private char sex;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", country='" + country + '\'' +
", sex=" + sex +
'}';
}
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 String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public Person() {
}
public Person(String name, Integer age, String country, char sex) {
this.name = name;
this.age = age;
this.country = country;
this.sex = sex;
}
}
5. 新增了日期时间类
Date日期时间类的缺点:
1.设计比较乱,Date日期在java.util和java.sql都有,而且它的时间格式转换类在java.text包下
2.线程不安全。
新增的日期时间类:
LocalDate: 表示日期类。yyyy-MM-dd
LocalTime: 表示时间类。 HH:mm:ss
LocalDateTime: 表示日期时间类 yyyy-MM-dd t HH:mm:ss sss
DatetimeFormatter:日期时间格式转换类。
Instant: 时间戳类。
Duration: 用于计算两个日期类
public class Test {
public static void main(String[] args) {
//获取当前日期
LocalDate now = LocalDate.now();
//指定日期
LocalDate date = LocalDate.of(2022, 8, 23);
//当前时间
LocalTime now1 = LocalTime.now();
LocalTime of = LocalTime.of(17, 30, 20, 600);
//获取当前日期时间
LocalDateTime now2 = LocalDateTime.now();
LocalDateTime now3 = LocalDateTime.of(2022,6,20,17,45,20);
Duration between = Duration.between(now2, now3);
System.out.println(between.toHours());
DateTimeFormatter dateTimeFormatter=DateTimeFormatter.ofPattern("yyyy-MM-dd");
//把字符串转换为日期格式
LocalDate parse = LocalDate.parse("1999-12-12", dateTimeFormatter);
//把日期格式转换为字符串
String format = parse.format(dateTimeFormatter);
}
}