文章目录
1. Lambda表达式
-
格式:
->
:lambda操作符 或箭头操作符- 左边:lambda形参列表,其实就是借口中的抽象方法的形参列表
- 右边:malbda体,气死就是重写的抽象方法的方法体
-
lambda表达式的使用
总结:
左边:lambda形参列表的参数类型可以省略(类型推断);如果lambda形参列表只有一个参数,其一对()也可以省略;
右边:lambda体应该使用一对{}包裹;如果lambda体只有一条执行语句(可能是return语句),可以省略这一对{}和return关键字。
- 无参,无返回值
Runnable r2 = () -> System.out.println("lambda表达式");
- lambda需要一个参数,但是没有返回值
Consumer<String> con = (String s) -> System.out.println(s);
- 数据类型可以省略,因为可由编译器推断得出,成为“类型推断”
Consumer<String> con = (s) -> System.out.println(s);
- lambda若只需要一个参数时,参数的小括号可以省略
Consumer<String> con = s -> System.out.println(s);
- Lambda 需要两个以上的参数,多条执行语句,并且可以有返回值
Comparator<Integer> comparator = (o1, o2) -> { System.out.println(o1); System.out.println(o2); return o1.compareTo(o2); };
- 当lambda体只有一条语句时,return与大括号都可以省略
- 无参,无返回值
-
lambda表达式的本质:作为函数式接口的实例;
-
如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口;
-
所以以前用匿名实现类表示的现在都可以用lambda表达式来写。
-
Java内置四大核心函数式接口
- Consumer 消费型接口 对类型为T的对象应用操作,包含方法
void accept(T t)
- Supplier 供给型接口 返回类型为T的对象,包含方法:
T get()
- Function<T, R> 函数型接口 对类型为T的对象应用操作,并返回结果,结果是R类型的对象。包含方法:
R apply(T t)
- Predicate 断定型接口 确定类型为T的对象是否满足某约束,并返回boolean值。包含方法:
boolean test(T t)
- Consumer 消费型接口 对类型为T的对象应用操作,包含方法
2. 方法引用与构造器引用
方法引用
-
使用场景:当要传递给lambda体的操作,已经有实现的方法了,可以使用方法引用。
-
方法引用,本质上就是lambda表达式,而lambda表达式作为函数式接口的实例,所以方法引用也是函数式接口的实例。
-
使用格式:
类(或对象)::方法名
-
具体分为以下情况:
-
对象::非静态方法
// 1. Consumer中的void accept(T t) PrintStream中的println(T t) PrintStream ps = System.out; Consumer<String> con = ps::println; con.accept("beijing"); // 2. Supplier中的T get() Employee中的getName() Employee emp = new Employee(); Supplier<String> sup = emp::getName; System.out.println(sup.get());
-
类::静态方法
// Comparator中的int compare(T t1, T t2); Integer中的int compare(T t1, T t2); Comparator<Integer> comp = Integer::compare; comp.compare(12, 24);
-
类::非静态方法
// Comparator中的int compare(T t1, T t2); String中的int t1.compareTo(t2); Comparator<String> comp = String::compareTo; comp.compare("abc", "abd");
-
构造器引用和数组引用
- 构造器引用:和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致 。抽象方法的返回值类型即位构造器所属的类的类型。
// Supplier<Employee> sup = () -> new Employee();
Supplier<Employee> sup = Employee::new;
- 数组引用:数组看作是一个特殊的类,和构造器引用类似。
// Function<Integer, String[]> func1 = length -> new String[length];
// func1.apply(2);
Funcion<Integer, String[]> func2 = String[] :: new;
func2.apply(2);
3. Stream API
- Stream 自己不会存储元素;
- Stream不会改变源对象。相反,他们会返回一个持有结果的新的Stream;
- Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
- 创建Stream:一个数据源
- 中间操作:对数据源的数据进行处理
- 终止操作:一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会在使用。
创建Stream
- 通过集合
default Stream<E> stream() {} // 创建一个串行流
default Stream<E> parallelStream() {} // 创建一个并行流
- 通过数组
public static <T> stream(T[] array) {} // 根据类型返回一个流
- 通过Stream的of()
public static<T> Stream<T> of(T... values) {}
- 创建无限流
// 迭代 遍历前10个偶数
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {}
Stream.iterate(0, t->t+2).limit(10).forEach(System.out::println);
// 生成 遍历前10个随机数
public static<T> Stream<T> generate(Supplier<T> s) {}
Stream.generate(Math::random).limit(10).forEach(System.out::println);
中间操作
- 筛选与切片
Stream<T> filter(Predicate<? super T> predicate); // 接收lambda,从流中排出元素
Stream<T> limit(long maxSize); // 截断流
Stream<T> skip(long n); // 跳过元素
Stream<T> distinct(); // 筛选,通过流所生成元素的 hashCode()和equals() 去除重复的元素
-
映射
- map(Function f) 接收一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被引用到每个元素上,并将其映射成一个新的元素。
//eg1: List<String> stringList = Arrays.asList("aa", "bb", "cc"); stringList.stream().map(str -> str.toUpperCase()).forEach(System.out::println); //eg2: 获取姓名长度大于3的名字 List<Employee> employeeList = EmployeeData.getEmployee(); employeeList.stream().map(Employee::getName).filter(name -> name.length()>2).forEach(System.out::println);
- flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连成一个流。
@Test public void test03() { List<String> stringList = Arrays.asList("aa", "bb", "cc"); // flatMap 类似add addAll Stream<Stream<Character>> streamStream = stringList.stream().map(StreamAPITest::fromStringToStream); streamStream.forEach(s->{ s.forEach(System.out::println); }); System.out.println("********"); Stream<Character> characterStream = stringList.stream().flatMap(StreamAPITest::fromStringToStream); characterStream.forEach(System.out::println); } public static Stream<Character> fromStringToStream(String str) { ArrayList<Character> list = new ArrayList<>(); for(Character c: str.toCharArray()) { list.add(c); } return list.stream(); }
-
排序
- sorted() 自然排序
- sorted(Comparator com) 定制排序
List<Employee> employees = EmployeeData.getEmployee(); employees.stream().sorted((o1, o2) -> Integer.compare(o1.getAge(),o2.getAge())).forEach(System.out::println); employees.stream().sorted(Comparator.comparingInt(Employee::getAge)).forEach(System.out::println);
终止操作
- 匹配和查找
1. boolean allMatch(Predicate<? super T> predicate); 检查是否匹配所有元素。
//是否所有员工年龄大于18
boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 18);
2. boolean anyMatch(Predicate<? super T> predicate); 检查是否匹配至少一个元素。
3. boolean noneMatch(Predicate<? super T> predicate); 检查是否没有匹配的元素,如果没有返回true
4. Optional<T> findFirst(); // 查找第一个元素
5. Optional<T> findAny(); // 查找任意一个元素
// 串行流返回第一个;并行流会返回任意一个
Optional<Employee> any = employees.parallelStream().findAny();
6. long count() 返回流中元素的个数
7. Optional<T> max(Comparator<? super T> comparator); 返回流中的最大值
// 最高的钱数
Optional<Double> max = employees.stream().map(Employee::getMoney).max(Double::compareTo);
8. Optional<T> min(Comparator<? super T> comparator); 返回流中的最小值
// 最低的钱数的员工
Optional<Employee> min = employees.stream().min(Comparator.comparingDouble(Employee::getMoney));
9. void forEach(Consumer<? super T> action);
- 归约:可以将流中的元素反复结合起来,得到一个值。返回T
1. T reduce(T identity, BinaryOperator<T> accumulator);
// 计算1-10的自然数的和
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer integer = list.stream().reduce(0, Integer::sum);//第一个参数初始值
2. Optional<T> reduce(BinaryOperator<T> accumulator); // 求和
List<Employee> employees = EmployeeData.getEmployee();
Optional<Double> reduce = employees.stream().map(Employee::getMoney).reduce(Double::sum);
Optional<Double> reduce2 = employees.stream().map(Employee::getMoney).reduce((d1,d2) -> d1+d2);
System.out.println(reduce);
System.out.println(reduce2);
- 收集
// collect(Collector c) 将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法。
List<Employee> employees = EmployeeData.getEmployee();
List<Employee> list = employees.stream().filter(e -> e.getMoney() > 200).collect(Collectors.toList());
list.forEach(System.out::println);
4. Optional类
- 最常见的空指针异常,为了解决空指针异常;
创建Optional类对象的方法
Optional.of(T t) 创建一个Optional实例,t必须非空;
Optional.empty() 创建一个空的Optional实例;
Optional.ofNullable(T t) t可以为null
判断Optional容器中是否包含对象
boolean isPresent() 判断是否包含对象
void ifPresent(Consumer<?super T> consumer) 如果有值,就执行Consumer接口的实现代码,并且该值回作为参数传递给他。
获取Optional容器的对象
T get() 如果调用对象包含值,返回该值,否则抛异常
T orElse(T other) 如果有值则将其返回,否则返回制定的other对象
T orElseGet(Supplier<?extends T> other) 如果有值则将其返回,否则返回由Supplier接口实现提供的对象。
T orElseThrow(Supplier<?extends T> exceptionSupplier) 如果有值则将其返回,否则跑出由Supplier接口实现提供的异常。
- 示例:
public String getGirlName(Boy boy) {
return boy.getGirl().getName();
}
public String getGirlName1(Boy boy) {
if (boy != null) {
Girl girl = boy.getGirl();
if (girl != null) {
return girl.getName();
}
}
return null;
}
public String getGirlName2(Boy boy) {
Optional<Boy> boyOptional = Optional.ofNullable(boy);
Boy boy1 = boyOptional.orElse(new Boy(new Girl("xiaoming")));
Girl girl = boy1.getGirl();
Optional<Girl> girlOptional = Optional.ofNullable(girl);
Girl girl1 = girlOptional.orElse(new Girl("xiaohong"));
return girl1.getName();
}
@Test
public void test02() {
String girlName = getGirlName2(new Boy());
System.out.println(girlName);
String girlName1 = getGirlName2(null);
System.out.println(girlName1);
}
5. 时间处理
包括:LocalDate、LocalTime、LocalDateTime
1. LocalDate
java中做时间处理时一般会采用java.util.Date,但是相比于Date来说,还有更好的选择 java.time.LocalDate。
LocalDate不包含时间,只是单纯的年月日
// 获取时间 返回值 意义 2020-01-21
getYear() // int 获取当前日期的年份 2020
getMonth() // Month 获取当前日期的月份对象 month对象 JANUARY 数字从0开始
getMonthValue() // int 获取当前日期是第几月 1
getDayOfWeek() // DayOfWeek 表示该对象表示的日期是星期几 TUESDAY 数字从0开始
getDayOfMonth() // int 表示该对象表示的日期是这个月第几天 21
getDayOfYear() // int 表示该对象表示的日期是今年第几天 21
// 如果传的值不正确,会报异常
withYear(int year) // LocalDate 修改当前对象的年份
withMonth(int month) // LocalDate 修改当前对象的月份
withDayOfMonth(int dayOfMonth) // LocalDate 修改当前对象在当月的日期
isLeapYear() // boolean 是否是闰年
lengthOfMonth() // int 这个月有多少天
lengthOfYear() // int 该对象表示的年份有多少天(365或者366)
// 计算
plusYears(long yearsToAdd) // LocalDate 当前对象增加指定的年份数
plusMonths(long monthsToAdd) // LocalDate 当前对象增加指定的月份数
plusWeeks(long weeksToAdd) // LocalDate 当前对象增加指定的周数
plusDays(long daysToAdd) // LocalDate 当前对象增加指定的天数
minusYears(long yearsToSubtract) // LocalDate 当前对象减去指定的年数
minusMonths(long monthsToSubtract) // LocalDate 当前对象减去注定的月数
minusWeeks(long weeksToSubtract) // LocalDate 当前对象减去指定的周数
minusDays(long daysToSubtract) // LocalDate 当前对象减去指定的天数
compareTo(ChronoLocalDate other) // int 比较当前对象和other对象在时间上的大小,返回值如果为正,则当前对象时间较晚,other更小
isBefore(ChronoLocalDate other) // boolean 比较当前对象日期是否在other对象日期之前
isAfter(ChronoLocalDate other) // boolean 比较当前对象日期是否在other对象日期之后
isEqual(ChronoLocalDate other) // boolean 比较两个日期对象是否相等
// 取当前日期:
LocalDate today = LocalDate.now(); // -> 2020-01-02
// 根据年月日取日期:
LocalDate crischristmas = LocalDate.of(2019, 12, 25); // -> 2019-12-25
// 根据字符串取:
LocalDate endOfFeb = LocalDate.parse("2020-01-20"); // 严格按照ISO yyyy-MM-dd验证,01写成1都不行
// 取本月第1天:
LocalDate firstDayOfThisMonth = today.with(TemporalAdjusters.firstDayOfMonth()); // 2020-01-01
// 取本月第2天:
LocalDate secondDayOfThisMonth = today.withDayOfMonth(2); // 2020-01-02
// 取本月最后一天,再也不用计算是28,29,30还是31:
LocalDate lastDayOfThisMonth = today.with(TemporalAdjusters.lastDayOfMonth()); // 2020-01-31
// 取下一天:
LocalDate firstDayOf2018 = lastDayOfThisMonth.plusDays(1); // 变成了2020-02-01
// 取2020年1月第一个周一
LocalDate firstMondayOf2020 = LocalDate.parse("2020-01-01").with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY)); // 2020-01-06
2. LocalTime
LocalTime只包含时间,获得当前时间:
// 构造时间
LocalTime now = LocalTime.now(); // 15:10:07.459
LocalTime zero = LocalTime.ofof(13, 55, 36); // 13:55:36
LocalTime date = LocalTime.of(13, 55, 36, 123);//13:55:36.000000123 微毫 10^9
LocalTime mid = LocalTime.parse("13:55:36"); // 13:55:36
LocalTime time = LocalTime.parse("13:55:36.123");//13:55:36.123
// 访问时分秒,用法与LocalDate类似
getHour()
getMinute()
getSecond()
getNano()
// LocalTime类包含一系列方法,能帮你完成时间计算,用法与LocalDate类似
plusHours()
plusMinutes()
plusSeconds()
plusNanos()
minusHours()
minusMinutes()
minusSeconds()
minusNanos()
3. LocalDateTime
// 构造时间
LocalDateTime nowDateTime = LocalDateTime.now(); //2020-01-21T15:07:39.980
LocalDateTime date = LocalDateTime.of(2020, 11, 26, 13, 55, 36, 123); //2020-11-26T13:55:36.000000123
LocalDateTime time = LocalDateTime.parse("2019-12-26T13:55:36.123"); //2019-12-26T13:55:36.123
// 访问日期时间,用法与LocalDate类似
getYear()
getMonth()
getDayOfMonth()
getDayOfWeek()
getDayOfYear()
getHour()
getMinute()
getSecond()
getNano()
// LocalDateTime类包含一系列方法,能帮你完成时间计算,用法与LocalDate类似
plusYears()
plusMonths()
plusDays()
plusHours()
plusMinutes()
plusSeconds()
plusNanos()
minusYears()
minusMonths()
minusDays()
minusHours()
minusMinutes()
minusSeconds()
minusNanos()
4. mybatis中和mysql交互
- 如果想要在JDBC中,使用Java8的日期LocalDate、LocalDateTime,则必须要求数据库驱动的版本不能低于4.2
LocalDate --> date
LocalTime --> time
LocalDateTime --> datetime
5. 相互转换
// localDateTime和string 互相转换
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
String timeToStr1 = dtf.format(now);
System.out.println("localDateTime转string:" + timeToStr1);
String timeToStr2 = now.format(dtf);
System.out.println("localDateTime转string:" + timeToStr2);
LocalDateTime strToTime = LocalDateTime.parse("2024-06-01 10:10", dtf);
System.out.println("string转localDateTime转:" + strToTime);
// Date和string 互相转换
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
try {
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
Date strToDate = sdf.parse("2024-06-01 10:10");
System.out.println("string转date:" + strToDate);
} catch (ParseException e) {
e.printStackTrace();
}
String dateToStr = sdf.format(new Date());
System.out.println("date转string:" + dateToStr);
// Date和localDateTime 互相转换
Date nowDate = new Date();
LocalDateTime localDateTime = nowDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
System.out.println("date转localDateTime:" +localDateTime);
Date date = Date.from(now.atZone(ZoneId.systemDefault()).toInstant());
System.out.println("localDateTime转date:" +date);