一、Lambda表达式
lambda表达式的语法:
(parameters) -> expression
或
(parameters) ->{ statements; }
(x)->{system.out.prinln} //直接打印x参数;
示例:
public class LambdaTest {
public static void main(String args[]){
//开启一个新的线程
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("新线程:"+Thread.currentThread().getName());
}
}).start();
System.out.println("主线程:"+Thread.currentThread().getName());
System.out.println("==============================");
/**
* Lambda表达式是一个匿名函数,可以理解为一段可传递的代码
* 优点:简化了匿名内部类的使用,语法更加简单。
*/
new Thread(() -> {
System.out.println("新线程lambda:"+Thread.currentThread().getName());
}).start();
System.out.println("==============================");
List<Person> list = new ArrayList<Person>();
list.add(new Person("薇恩",20));
list.add(new Person("亚索",30));
list.add(new Person("德玛西亚",18));
Collections.sort(list,(p1,p2) -> p1.age-p2.age);
for (Person p: list) {
System.out.println("用户信息=>"+p.toString());
}
}
}
执行结果:
主线程:main
新线程:Thread-0
==============================
==============================
新线程lambda:Thread-1
用户信息=>Person(name=德玛西亚, age=18)
用户信息=>Person(name=薇恩, age=20)
用户信息=>Person(name=亚索, age=30)
二、函数式接口
函数式接口 | 参数类型 | 返回类型 | 说明 |
---|---|---|---|
Function< T, R > 函数型接口 | T | R | R apply(T t):对类型为T的对象应用操作,并返回类型为R类型的对象。 |
Consumer< T > 消费型接口 | T | void | void accept(T t):对类型为T的对象应用操作。 |
Supplier< T > 供给型接口 | 无 | T | T get():返回类型为T的对象。 |
Predicate< T > 断言型接口 | T | boolean | boolean test(T t):确定类型为T的对象是否满足条件,并返回boolean类型。 |
1. Function<T, R>: 函数型接口【R apply(T t)】
示例:
public class FunctionTest {
public static void main(String[] args) {
//奖金额翻10倍
test(money -> Integer.parseInt(money)*10,"123");
}
public static void test(Function<String, Integer> function, String text) {
//apply是一个有参有返回值的抽象方法
Integer money = function.apply(text);
System.out.println("money:"+money); // money:1230
}
}
2. Consumer< T >: 消费型接口【void accept(T t)】
示例:
public class ConsumerTest {
public static void main(String[] args) {
toLowcase(msg -> System.out.println("转小写:"+msg.toLowerCase()), //转小写:hello world
msg -> System.out.println("转大写:"+msg.toUpperCase()) //转大写:HELLO WORLD
,"Hello World");
}
public static void toLowcase(Consumer<String> c1,Consumer<String> c2, String text){
//accept是一个有参无返回值的抽象方法
//andThen 默认方法,先执行前面的,再执行后面的
c1.andThen(c2).accept(text);
}
}
3. Supplier< T >: 供给型接口【T get()】
示例:
public class SupplierTest {
public static void main(String[] args) {
fun1(() -> {
int arr[] = {1,9,5,2,3};
//排序
Arrays.sort(arr);
//返回最大值
return arr[arr.length-1];
});
}
public static void fun1(Supplier<Integer> supplier) {
//get是一个无参有返回值的抽象方法
Integer max = supplier.get();
System.out.println("Max = "+max); // Max = 9
}
}
4. Predicate< T >: 断言型接口【boolean test(T t)】
示例:
public class PredicateTest {
public static void main(String[] args) {
//判断长度是否大于3
test(msg -> msg.length()>3,"HelloWorld");
}
public static void test(Predicate<String> predicate, String text) {
//test是一个有参有返回值(boolean)的抽象方法
boolean b = predicate.test(text);
System.out.println("b:"+b); // b:true
}
}
三、流API(Stream API)
1. 基础用法(forEach | filter | count | limit | skip | map | sorted | distinct | reduce | concat等)
示例:
public class StreamTest {
public static void main(String args[]){
//forEach、filter (元素循环/过滤)
Stream.of("a1","a2","a3")
.filter(s -> s.contains("1"))
.forEach(s -> System.out.println(s)); // a1
System.out.println("==========================");
//count (元素计数)
long count = Stream.of("a1","a2","a3")
.count();
System.out.println(count); // 3
System.out.println("==========================");
//limit (截取前面的几个元素)
Stream.of("a1","a2","a3")
.limit(2)
.forEach(System.out::println); // a1 a2
System.out.println("==========================");
//skip (跳过前面的几个元素)
Stream.of("a1","a2","a3")
.skip(2)
.forEach(System.out::println); // a3
System.out.println("==========================");
//map (将流中的元素映射到另一个流中)
Stream.of("1","2","3")
.map(Integer::parseInt)
.forEach(System.out::println); // 1 2 3
System.out.println("==========================");
//sorted (元素排序)
Stream.of("1","3","2","5","11")
.sorted(Comparator.comparingInt(Integer::parseInt))
.forEach(System.out::println); // 1 2 3 5 11
System.out.println("==========================");
//distinct (元素去重)
Stream.of("1","3","2","5","1")
.distinct()
.forEach(System.out::println); // 1 3 2 5
System.out.println("==========================");
//reduce (缩减)
Integer sum = Stream.of(1,3,2,5)
//identity 为初始值
//x:第一次会将默认值赋给x,后面将上一次的和复赋值给x
//y:每次循环的值
.reduce(0,(x,y) -> {
System.out.println("x="+x+",y="+y);
// x=0,y=1
// x=1,y=3
// x=4,y=2
// x=6,y=5
return x + y;
});
System.out.println("sum:"+sum); // sum:11
//获取最大值
Integer max = Stream.of(1, 3, 2, 5)
//identity 为初始值
//x:第一次会将默认值赋给x,后面将上一次的和复赋值给x
//y:每次循环的值
.reduce(0, (x, y) -> x > y ? x : y);
System.out.println("max:"+max); // max:5
System.out.println("==========================");
//map与reduce混合使用
Integer sum2 = Stream.of(
new Person("张三", 18),
new Person("李四", 22),
new Person("王五", 17)
)
.map(Person::getAge) //收集年龄
//.reduce(0,(x, y) -> x + y);
.reduce(0,Integer::sum); //计算总数
//.reduce(0,Integer::max); //取最大值
System.out.println("sum2="+sum2); // sum2=57
System.out.println("==========================");
//concat (连接)
Stream<String> s1 = Stream.of("aa","bb","cc");
Stream<String> s2 = Stream.of("dd","ee","ff");
Stream.concat(s1,s2).forEach(System.out::println);// aa bb cc dd ee ff
System.out.println("====================================");
//数据收集
//收集到List
List<String> list = Stream.of("aa", "bb", "cc", "aa").collect(Collectors.toList());
System.out.println("收集到List:"+list.toString()); // 收集到List:[aa, bb, cc, aa]
//收集到Set
Set<String> set = Stream.of("aa", "bb", "cc", "aa").collect(Collectors.toSet());
System.out.println("收集到Set:"+set.toString()); // 收集到Set:[aa, bb, cc]
//收集到ArrayList
ArrayList<String> arrayList = Stream.of("aa", "bb", "cc", "aa").collect(Collectors.toCollection(() -> new ArrayList<String>()));
System.out.println("收集到ArrayList:"+arrayList.toString()); // 收集到ArrayList:[aa, bb, cc, aa]
//收集到数组
String[] strings = Stream.of("aa", "bb", "cc", "aa")
.toArray(String[]::new); //简写
System.out.println("收集到数组:"+Arrays.toString(strings)); // 收集到数组:[aa, bb, cc, aa]
System.out.println("============================");
//聚合运算
Optional<Person> collect = Stream.of(
new Person("张三", 18),
new Person("李四", 22),
new Person("王五", 17)
).max(Comparator.comparingInt(Person::getAge));
System.out.println("最大年龄:"+collect.get()); // 最大年龄:Person(name=李四, age=22)
}
}
2. 高级用法
示例:
public class StreamExpertTest {
/**
* 用户对象
*/
static class User{
// 项目
private String name;
// 年龄
private int age;
// 爱好
private String[] hobbies;
public User(String name, int age, String[] hobbies) {
this.name = name;
this.age = age;
this.hobbies = hobbies;
}
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 String[] getHobbies() {
return hobbies;
}
public void setHobbies(String[] hobbies) {
this.hobbies = hobbies;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", hobbies=" + Arrays.toString(hobbies) +
'}';
}
}
public static void main(String[] args) {
// 初始化数据
List<User> users = Arrays.asList(
new User("张三", 22, new String[]{"足球", "篮球"}),
new User("李四", 24, new String[]{"骑行", "爬山"}),
new User("王五", 30, new String[]{"骑行", "撸代码"}),
new User("赵六", 22, new String[]{"篮球", "乒乓球"}),
new User("张七", 25, new String[]{"爬山", "撸代码"})
);
// 需求1:收集所有的用户姓名,并用逗号分割
String names = users.stream()
.map(User::getName)
.collect(Collectors.joining(","));
System.out.println("names=" + names); // names=张三,李四,王五,赵六,张七
// 需求2:收集年龄为22的用户人数
long count = users.stream()
.filter(user -> user.getAge() == 22)
.count();
System.out.println("count=" + count); // count=2
// 需求3:收集各年龄人数
Map<Integer, Long> collect = users.stream()
.collect(Collectors.groupingBy(User::getAge, Collectors.counting()));
System.out.println("collect=" + collect); // collect={22=2, 24=1, 25=1, 30=1}
// 需求4:收集所有爱好为字符串,逗号分隔,并去重
String hobbies = users.stream()
.flatMap(user -> Arrays.stream(user.getHobbies()))
.distinct()
.collect(Collectors.joining(","));
System.out.println("hobbies=" + hobbies); // hobbies=足球,篮球,骑行,爬山,撸代码,乒乓球
// 需求5:收集各自爱好为字符串,逗号分隔
Map<String, String> userHobby = users.stream()
.collect(Collectors.toMap(User::getName, user -> Arrays.toString(user.getHobbies())));
System.out.println("userHobby=" + userHobby); // userHobby={李四=[骑行, 爬山], 张三=[足球, 篮球], 王五=[骑行, 撸代码], 张七=[爬山, 撸代码], 赵六=[篮球, 乒乓球]}
// 需求6:收集hobbies为字符串数组List<String[]>
List<String[]> hobbiesList = Arrays.stream(hobbies.split(","))
.map(str -> new String[]{str})
.collect(Collectors.toList());
hobbiesList.stream().map(Arrays::toString).forEach(System.out::println);
// [足球]
// [篮球]
// [骑行]
// [爬山]
// [撸代码]
// [乒乓球]
// 需求7:按年龄进行排序
List<User> sortUsers = users.stream()
.sorted(Comparator.comparingInt(User::getAge))
.collect(Collectors.toList());
sortUsers.forEach(System.out::println);
// User{name='张三', age=22, hobbies=[足球, 篮球]}
// User{name='赵六', age=22, hobbies=[篮球, 乒乓球]}
// User{name='李四', age=24, hobbies=[骑行, 爬山]}
// User{name='张七', age=25, hobbies=[爬山, 撸代码]}
// User{name='王五', age=30, hobbies=[骑行, 撸代码]}
// 需求8:收集年龄大于22的用户
List<User> collectUsers = users.stream()
.filter(user -> user.getAge() > 22)
.collect(Collectors.toList());
collectUsers.forEach(System.out::println);
// User{name='李四', age=24, hobbies=[骑行, 爬山]}
// User{name='王五', age=30, hobbies=[骑行, 撸代码]}
// User{name='张七', age=25, hobbies=[爬山, 撸代码]}
// 需求9:收集爱好包含骑行的用户
List<User> collectUsers2 = users.stream()
.filter(user -> Arrays.stream(user.getHobbies()).anyMatch(hobby -> hobby.contains("骑行")))
.collect(Collectors.toList());
collectUsers2.forEach(System.out::println);
// User{name='李四', age=24, hobbies=[骑行, 爬山]}
// User{name='王五', age=30, hobbies=[骑行, 撸代码]}
// 需求10:收集姓名是张开头的用户
// 创建一个 Predicate,用于判断名字是否以 "张" 开头
Predicate<User> startsWithZ = user -> user.getName().startsWith("张");
List<User> collectUsers3 = users.stream().filter(startsWithZ).collect(Collectors.toList());
collectUsers3.forEach(System.out::println);
// User{name='张三', age=22, hobbies=[足球, 篮球]}
// User{name='张七', age=25, hobbies=[爬山, 撸代码]}
// 需求11:收集用户姓名和爱好为Map<String, String[]>
Map<String, String[]> userMap = users.stream()
.collect(Collectors.toMap(
User::getName, // 名称
User::getHobbies, // 爱好
(oldValue, newValue) -> oldValue, // 如果名称重复,保留旧值
LinkedHashMap::new // 使用LinkedHashMap保持顺序
));
userMap.forEach((key, value) -> System.out.println(key + "=" + Arrays.toString(value)));
// 张三=[足球, 篮球]
// 李四=[骑行, 爬山]
// 王五=[骑行, 撸代码]
// 赵六=[篮球, 乒乓球]
// 张七=[爬山, 撸代码]
// 需求12:收集用户姓名和用户对象为Map<String, User>
Map<String, User> userMap2 = users.stream()
.collect(Collectors.toMap(
User::getName, // 名称
Function.identity(), // 值映射函数,直接使用对象本身
(oldValue, newValue) -> oldValue, // 如果名称重复,保留旧值
LinkedHashMap::new // 使用LinkedHashMap保持顺序
));
userMap2.forEach((key, value) -> System.out.println(key + "=" + value));
// 张三=User{name='张三', age=22, hobbies=[足球, 篮球]}
// 李四=User{name='李四', age=24, hobbies=[骑行, 爬山]}
// 王五=User{name='王五', age=30, hobbies=[骑行, 撸代码]}
// 赵六=User{name='赵六', age=22, hobbies=[篮球, 乒乓球]}
// 张七=User{name='张七', age=25, hobbies=[爬山, 撸代码]}
// 需求13:收集用户信息为固定格式,对象信息为数组字符串
// 例如:"[{\"name\":\"张三\"}...]"
Map<String, String> userMap3 = users.stream()
.collect(Collectors.groupingBy(
User::getName, // 用户姓名-key
Collectors.mapping( // 映射为固定格式的对象信息
user -> "{\"name\":\"" + user.getName() + "\",\"age\":\"" + user.getAge() + "\",\"hobbies\":\"" + Arrays.toString(user.getHobbies()) + "\"}",
Collectors.joining(",", "[", "]")
)
));
userMap3.forEach((key, value) -> System.out.println(key + "=" + value));
// 李四=[{"name":"李四","age":"24","hobbies":"[骑行, 爬山]"}]
// 张三=[{"name":"张三","age":"22","hobbies":"[足球, 篮球]"}]
// 王五=[{"name":"王五","age":"30","hobbies":"[骑行, 撸代码]"}]
// 张七=[{"name":"张七","age":"25","hobbies":"[爬山, 撸代码]"}]
// 赵六=[{"name":"赵六","age":"22","hobbies":"[篮球, 乒乓球]"}]
}
}
四、默认方法(default关键字修饰)
示例:
public interface StudyInterface {
/**
* 静态接口-学习
*/
void study();
/**
* 默认接口-展示(default 关键字修饰)
* 实现类可以根据具体需求是否需要实现该接口
*/
default void show(){
System.out.println("默认接口-show");
}
}
五、时间API
示例:
public class LocalDateTest {
public static void main(String args[]){
//日期的操作
LocalDate date = LocalDate.of(2024,10,25);
System.out.println("date = "+date); // date = 2024-10-25
//获取当前时间
LocalDate now = LocalDate.now();
System.out.println("now = "+now); // now = 2024-10-25
System.out.println("年:"+now.getYear()); // 年:2024
System.out.println("月:"+now.getMonth().getValue()); // 月:10
System.out.println("日:"+now.getDayOfMonth()); // 日:25
System.out.println("星期:"+now.getDayOfWeek().getValue()); // 星期:5
System.out.println("===================================");
//时间的操作
LocalTime time = LocalTime.of(1,11,11);
System.out.println("time = "+time); // time = 01:11:11
LocalTime now1 = LocalTime.now();
System.out.println("now1 = "+now1); // now1 = 14:55:59.931
System.out.println(now1.getHour()); // 14
System.out.println(now1.getMinute()); // 55
System.out.println(now1.getSecond()); // 59
System.out.println(now1.getNano()); // 931000000
System.out.println("===========================");
//获取当前日期时间
LocalDateTime now3 = LocalDateTime.now();
System.out.println("now3 = "+now3); // now3 = 2024-10-25T14:55:59.931
//修改日期 修改后会返回一个新的日期对象,不会修改原来的值
LocalDateTime date1 = now3.withYear(2023);
System.out.println("原来日期:"+now3); // 原来日期:2024-10-25T14:55:59.931
System.out.println("修改后日期:"+date1); // 修改后日期:2023-10-25T14:55:59.931
//日期加减
System.out.println("1年后:"+now3.plusYears(1)); // 1年后:2025-10-25T14:55:59.931
System.out.println("6个月后:"+now3.plusMonths(6)); // 6个月后:2025-04-25T14:55:59.931
System.out.println("10年前:"+now3.minusYears(10)); // 10年前:2014-10-25T14:55:59.931
System.out.println("3天前:"+now3.minusDays(3)); // 3天前:2024-10-22T14:55:59.931
//格式化日期
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String nowStr = format.format(now3);
System.out.println("nowStr:"+nowStr); // nowStr:2024-10-25 14:55:59
//将字符串解析为日期
LocalDateTime parse = LocalDateTime.parse("2020-03-13 22:22:11",format);
System.out.println("解析后日期:"+parse); // 解析后日期:2020-03-13T22:22:11
//时间差 Duration
Duration du = Duration.between(time,now1);
System.out.println("相差天数:"+du.toDays()); // 相差天数:0
System.out.println("相差小时数:"+du.toHours()); // 相差小时数:13
System.out.println("相差分钟数:"+du.toMinutes()); // 相差分钟数:824
//时间差 Period
Period pe = Period.between(date,now);
System.out.println("相差天数:"+pe.getDays()); // 相差天数:0
}
}