文章目录
1Lambda表达式
1.1标准格式
(参数列表) -> {}
方法的参数是接口类型可以考虑用Lambda表达式
无参数无返回值
public interface EatAble {
public abstract void eat();
}
public class LambdaDemo {
public static void main(String[] args) {
doEat(() -> {
System.out.println("eat food");
});
}
private static void doEat(EatAble e) {
e.eat();
}
}
有参数有返回值
public interface DriveAble {
public abstract String drive(String name);
}
public class LambdaDemo {
public static void main(String[] args) {
doDrive((String name) -> {
System.out.println("drive " + name);
return name;
});
}
private static void doDrive(DriveAble d) {
String car = d.drive("byd");
System.out.println("car=" + car);
}
}
1.2底层原理
匿名内部类:编译后生成一个新的类
Lambda表达式:编译后生成一个私有静态方法,表达式的代码会放到方法中,实际上也会生成一个匿名内部类重写抽象方法
1.3省略格式
-
小括号内参数类型可以省略
-
小括号只有一个参数,括号可以省略
-
大括号只有一个语句,可以省略大括号、return、分号
1.4前提条件
-
方法参数或局部变量为接口
-
接口只有一个抽象方法(函数式接口)
@FunctionalInterface // 检测接口是否只有一个抽象方法
public interface EatAble {
public abstract void eat();
}
1.5和匿名内部类对比
-
匿名内部类需要的类型是类,抽象类,接口;Lambda需要的类型是接口
-
匿名内部类的抽象方法数量任意;Lambda的抽象方法只有一个
-
匿名内部类编译后形成class;Lambda运行时动态生成class
1.6接口默认方法
实现类可以不重写默认方法,也可以重写
public interface DriveAble {
public abstract String drive(String name);
default void print() {
System.out.println("print");
}
}
public class MyDrive implements DriveAble {
@Override
public String drive(String name) {
return null;
}
}
1.7接口静态方法
实现类无法重写、无法调用静态方法
public interface DriveAble {
static void create() {
System.out.println("create");
}
}
1.8常用内置函数式接口
1.8.1Supplier
供给型接口
public class SupplierDemo {
public static void main(String[] args) {
printMax(() -> {
int[] array = {1, 2, 3};
Arrays.sort(array);
return array[array.length - 1];
});
}
private static void printMax(Supplier<Integer> supplier) {
Integer value = supplier.get();
System.out.println("value=" + value);
}
}
1.8.2Consumer
消费型接口
public class ConsumerDemo {
public static void main(String[] args) {
print((String s) -> {
System.out.println("upper case=" + s.toUpperCase());
});
}
private static void print(Consumer<String> consumer) {
consumer.accept("hello");
}
}
public class ConsumerDemo2 {
public static void main(String[] args) {
print((String s) -> {
System.out.println("upper case=" + s.toUpperCase());
}, (String s) -> {
System.out.println("lower case=" + s.toLowerCase());
});
}
private static void print(Consumer<String> c1, Consumer<String> c2) {
// 先调用c1后调用c2
c1.andThen(c2).accept("Hello");
}
}
1.8.3Function
类型转换接口
public class FunctionDemo {
public static void main(String[] args) {
getNumber((String s) -> {
return Integer.parseInt(s);
});
}
private static void getNumber(Function<String, Integer> function) {
Integer num = function.apply("10");
System.out.println(num);
}
}
public class FunctionDemo2 {
public static void main(String[] args) {
getNumber((String s) -> {
return Integer.parseInt(s);
}, (Integer i) -> {
return i * 5;
});
}
private static void getNumber(Function<String, Integer> f1, Function<Integer, Integer> f2) {
Integer num = f1.andThen(f2).apply("10");
System.out.println(num);
}
}
1.8.4Predicate
判断型接口
public class PredicateDemo {
public static void main(String[] args) {
isGreaterThanTen((Integer i) -> {
return i > 10;
});
}
private static void isGreaterThanTen(Predicate<Integer> predicate) {
boolean flag = predicate.test(13);
System.out.println(flag);
}
}
public class PredicateDemo2 {
public static void main(String[] args) {
isGreaterThanTen((Integer i) -> {
return i > 10;
}, (Integer i) -> {
return i < 15;
});
}
private static void isGreaterThanTen(Predicate<Integer> p1, Predicate<Integer> p2) {
boolean flag = p1.and(p2).test(13);
System.out.println(flag);
}
}
1.9方法引用
格式:::
常见引用方式
-
对象::方法名
-
类名::静态方法
-
类名::普通方法
-
类名::new
-
数组::new
1.9.1对象名::引用成员方法
被引用的方法,参数要和接口中抽象方法的参数一样
接口抽象方法有返回值,被引用的方法必须有返回值
public static void main(String[] args) {
Date date = new Date();
Supplier<Long> supplier = date::getTime;
System.out.println(supplier.get());
}
1.9.2类名::静态方法
public static void main(String[] args) {
Supplier<Long> supplier = System::currentTimeMillis;
System.out.println(supplier.get());
}
1.9.3类名::引用实例方法
将第一个参数作为方法的调用者
public static void main(String[] args) {
Function<String, Integer> function = String::length;
System.out.println(function.apply("hello"));
}
public static void main(String[] args) {
BiFunction<String, Integer, String> biFunction = String::substring;
System.out.println(biFunction.apply("hello", 1));
}
1.9.4类名::new引用构造方法
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static void main(String[] args) {
Supplier<Person> supplier = Person::new;
System.out.println(supplier.get());
}
1.9.5数组::new引用数组构造方法
public static void main(String[] args) {
Function<Integer, int[]> function = int[]::new;
int[] array = function.apply(5);
System.out.println(Arrays.toString(array));
}
2Stream流操作
类似于生产流水线,不是一种数据结构,不保存数据,只是对数据加工
2.1获取Stream
根据Collection获取
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
Stream.of获取
基本类型的数组不可用
String[] strings = new String[]{"123", "456"};
Stream<String> stream1 = Stream.of(strings);
2.2注意事项
Stream只能操作一次
Stream方法返回的是新的流
Stream不调用终结方法,中间操作不会执行
2.3常用方法
2.3.1forEach遍历
List<String> list = new ArrayList<>();
Collections.addAll(list, "123", "456");
list.stream().forEach(System.out::println);
2.3.2count统计
List<String> list = new ArrayList<>();
Collections.addAll(list, "123", "456");
System.out.println(list.stream().count());
2.3.3filter过滤
List<String> list = new ArrayList<>();
Collections.addAll(list, "123", "456", "78");
list.stream().filter(s -> s.length() == 2).forEach(System.out::println)
2.3.4limit截取
List<String> list = new ArrayList<>();
Collections.addAll(list, "123", "456", "78");
list.stream().limit(2).forEach(System.out::println);
2.3.5skip跳过
List<String> list = new ArrayList<>();
Collections.addAll(list, "123", "456", "78");
list.stream().skip(2).forEach(System.out::println);
2.3.6map映射
List<String> list = new ArrayList<>();
Collections.addAll(list, "123", "456", "78");
list.stream().map(Integer::parseInt).forEach(System.out::println);
2.3.7sorted排序
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 123, 456, 78);
list.stream().sorted((i1, i2) -> i2 - i1).forEach(System.out::println);
2.3.8distinct去重
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 123, 456, 78, 123);
list.stream().distinct().forEach(System.out::println);
如果Stream是自定义类型,需要重写equals, hashCode方法
2.3.9match匹配
allMatch全部匹配
anyMatch任意匹配
nonMatch全部不匹配
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 123, 456, 78, 123);
System.out.println(list.stream().allMatch(i -> i > 0));
2.3.10find查找
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 123, 456, 78, 123);
Optional<Integer> first = list.stream().findFirst();
System.out.println(first.get());
2.3.11max,min最大最小
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 123, 456, 78, 123);
Optional<Integer> max = list.stream().max((i1, i2) -> i1 - i2);
System.out.println(max.get());
2.3.12reduce归纳
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3, 4);
Integer reduce = list.stream().reduce(0, (a, b) -> a + b);
System.out.println(reduce);
2.3.13mapToInt转为int
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3, 4);
list.stream().mapToInt(Integer::intValue).filter(i -> i > 2).forEach(System.out::println);
2.3.14concat合并
合并后不能操作之前的流
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2);
List<Integer> list2 = new ArrayList<>();
Collections.addAll(list2, 3, 4);
Stream.concat(list.stream(), list2.stream()).forEach(System.out::println);
2.4收集结果
2.4.1收集到集合、数组
Stream<String> stream = Stream.of("123", "456");
List<String> list = stream.collect(Collectors.toList());
Stream<String> stream = Stream.of("123", "456");
String[] array = stream.toArray(String[]::new);
2.4.2聚合
最大值:maxBy
最小值:minBy
平均:averagingInt
求和:summingInt
统计:counting
Stream<Student> stream = Stream.of(new Student(10), new Student(20));
Optional<Student> max = stream.collect(Collectors.maxBy((s1, s2) -> s1.getAge() - s2.getAge()));
System.out.println(max.get());
2.4.3分组
Stream<Student> stream = Stream.of(new Student(10), new Student(10), new Student(20));
Map<Integer, List<Student>> map = stream.collect(Collectors.groupingBy(Student::getAge));
map.forEach((k, v) -> System.out.println("k=" + k + ",v=" + v));
多级分组
Stream<Student> stream = Stream.of(new Student(10, "male"), new Student(10, "female"), new Student(20, "male"));
Map<Integer, Map<String, List<Student>>> map = stream.collect(Collectors.groupingBy(Student::getAge, Collectors.groupingBy(Student::getGender)));
map.forEach((k ,v) -> {
System.out.println("k=" + k);
v.forEach((k2, v2) -> System.out.println("k2=" + k2 + ",v2=" + v2));
});
2.4.4分区
Stream<Student> stream = Stream.of(new Student(10), new Student(10), new Student(20));
Map<Boolean, List<Student>> map = stream.collect(Collectors.partitioningBy(s -> s.getAge() > 15));
map.forEach((k, v) -> System.out.println("k=" + k + ",v=" + v));
2.4.5拼接
Stream<Student> stream = Stream.of(new Student(10, "male"), new Student(10, "female"), new Student(20, "male"));
String string = stream.map(Student::getGender).collect(Collectors.joining(","));
System.out.println(string);
2.5并行Stream流
多线程处理
2.5.1获取并行流
List<Integer> list = new ArrayList<>();
// 直接获取
Stream<Integer> parallelStream = list.parallelStream();
// 串行转并行
Stream<Integer> parallelStream2 = Stream.of(1, 2, 3, 4, 5).parallel();
2.5.2线程安全
加同步代码块
List<Integer> list = new ArrayList<>();
Object obj = new Object();
IntStream.rangeClosed(1, 1000).parallel().forEach(i -> {
synchronized (obj) {
list.add(i);
}
});
System.out.println(list.size());
使用线程安全集合
Vector<Integer> list = new Vector<>();
Object obj = new Object();
IntStream.rangeClosed(1, 1000).parallel().forEach(i -> {
list.add(i);
});
System.out.println(list.size());
List<Integer> list2 = new ArrayList<>();
List<Integer> synchronizedList = Collections.synchronizedList(list2);
使用collect/toArray
List<Integer> list = IntStream.rangeClosed(1, 1000).parallel().boxed().collect(Collectors.toList());
System.out.println(list.size());
2.5.3Fork/Join框架
分治,一个大任务拆分成很多小任务异步执行
工作窃取算法
2.6Optional
防止空指针异常
创建Optional对象
Optional<String> o1 = Optional.of("123");
Optional<Object> o2 = Optional.ofNullable(null);
Optional<Object> o3 = Optional.empty();
获取值
Optional<String> o1 = Optional.of("123");
if (o1.isPresent()) {
System.out.println(o1.get());
}
其它方法
Optional<Object> o2 = Optional.ofNullable(null);
String s = (String) o2.orElse("45");
Optional<String> o1 = Optional.of("123");
o1.ifPresent(str -> System.out.println("has value"));
Optional<String> o4 = Optional.of("ABC");
System.out.println(o4.map(String::toLowerCase).get());
3日期时间API
旧版日期时间API存在设计不合理、非线程安全、时区处理麻烦等问题
3.1日期时间类
LocalDate
LocalDate now = LocalDate.now();
LocalDate localDate = LocalDate.of(2024, 6, 1);
LocalTime
LocalTime now = LocalTime.now();
LocalTime localTime = LocalTime.of(14, 10, 10);
LocalDateTime
LocalDateTime now = LocalDateTime.now();
LocalDateTime localDateTime = LocalDateTime.of(2024, 1, 1, 10, 10, 9);
修改
LocalDateTime now = LocalDateTime.now();
System.out.println(now.withHour(20));
增加或减少
LocalDateTime now = LocalDateTime.now();
System.out.println(now.plusYears(1));
System.out.println(now.minusDays(10));
比较
LocalDateTime now = LocalDateTime.now();
LocalDateTime localDateTime = LocalDateTime.of(2024, 1, 1, 10, 10, 9);
System.out.println(now.isAfter(localDateTime));
System.out.println(now.isBefore(localDateTime));
System.out.println(now.isEqual(localDateTime));
3.2时间格式化与解析
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println(now.format(dtf));
System.out.println(LocalDateTime.parse("2024-01-01 10:00:00", dtf));
3.3Instant
表示时间戳
Instant now = Instant.now();
System.out.println(now);
System.out.println(now.plusSeconds(10));
System.out.println(now.minusSeconds(5));
System.out.println(now.getNano());
3.4日期时间差
后面减去前面
时间差
LocalTime now = LocalTime.now();
LocalTime localTime = LocalTime.of(23, 10, 10);
Duration duration = Duration.between(now, localTime);
System.out.println(duration.toHours());
System.out.println(duration.toMinutes());
System.out.println(duration.getSeconds());
日期差
LocalDate now = LocalDate.now();
LocalDate localDate = LocalDate.of(2024, 6, 1);
Period period = Period.between(localDate, now);
System.out.println(period.getYears());
System.out.println(period.getMonths());
System.out.println(period.getDays());
3.5时间调整
LocalDateTime now = LocalDateTime.now();
System.out.println(now.with(TemporalAdjusters.firstDayOfNextYear()));
3.6设置时区
获取所有时区
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
标准时区
ZonedDateTime.now(Clock.systemUTC())
默认时区
ZonedDateTime.now()
指定时区
ZonedDateTime.now(ZoneId.of("Asia/Shanghai"))
修改时区、时间
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
zonedDateTime.withZoneSameInstant(ZoneId.of("Europe/Monaco"))
修改时区、不改时间
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
zonedDateTime.withZoneSameLocal(ZoneId.of("Europe/Monaco"))
4重复注解与类型注解
4.1重复注解
@Config("abc")
@Config("def")
public class RepeatAnnotationDemo {
public static void main(String[] args) {
Config[] annotations = RepeatAnnotationDemo.class.getAnnotationsByType(Config.class);
for (Config config : annotations) {
System.out.println(config);
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface Configs {
Config[] value();
}
@Repeatable(Configs.class)
@Retention(RetentionPolicy.RUNTIME)
@interface Config {
String value();
}
4.2类型注解
@Target元注解新增了两种类型
TYPE_PARAMETER:可以写在类型参数的声明语句
public class TypeAnnotationDemo<@Type T> {
}
@Target(ElementType.TYPE_PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@interface Type {
}
TYPE_USE:可以在任何用到类型的地方使用
public class TypeAnnotationDemo {
@Type2
private int i = 5;
public int sum(@Type2 int a, @Type2 int b) {
return a + b;
}
}
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
@interface Type2 {
}
源码仓库:gitee