一、Lambda表达式
使用Lambda表达式,实际就是创建出该接口的实例对象。
1.1 创建线程
使用Labmda表达式需要函数式编程接口。
@Test
public void test1() {
// 匿名内部类创建线程!
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类创建线程!");
}
}).start();
// Lambda创建线程
new Thread(() -> System.out.println("Lambda创建线程")).start();
}
// 表达式
() -> {}
// 方法参数
()
// 方法要实现的内容,具体实现只有一段代码可以省略{}
{}
// 总结
使用Lambda表达式创建线程的时候,并不关心接口名,方法名,参数名。只关注他的参数类型,参数个数,返回值。
二、Stream流
2.1 集合操作
排序一个集合并遍历。
@Test
public void test1() {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
list.stream().sorted((i1, i2) -> i2 - i1).forEach((System.out::println));
}
结果
10
9
8
7
6
5
4
3
2
1
常用操作
@Test
public void test2() {
List<StreamVo> streamVos = new ArrayList<>();
streamVos.add(new StreamVo("啊吴", 2, "男"));
streamVos.add(new StreamVo("啊多", 3, "女"));
streamVos.add(new StreamVo("啊强", 44, "男"));
streamVos.add(new StreamVo("小吴", 11, "女"));
streamVos.add(new StreamVo("小多", 22, "女"));
streamVos.add(new StreamVo("小小强", 33, "女"));
streamVos.add(new StreamVo("小强强", 33, "男"));
// 找出姓小的
List<StreamVo> streamVos1 = new ArrayList<>();
for (StreamVo streamVo : streamVos) {
if (streamVo.getName().startsWith("小")) {
streamVos1.add(streamVo);
}
}
System.out.println(streamVos1);
// 接着找出名字为3个的
List<StreamVo> streamVos2 = new ArrayList<>();
for (StreamVo streamVo : streamVos1) {
if (streamVo.getName().length() == 3) {
streamVos2.add(streamVo);
}
}
System.out.println(streamVos2);
// 接着找出性别为男的
List<StreamVo> streamVos3 = new ArrayList<>();
for (StreamVo streamVo : streamVos2) {
if (streamVo.getSex().equals("男")) {
streamVos3.add(streamVo);
}
}
System.out.println(streamVos3);
// 接着遍历
for (StreamVo streamVo : streamVos3) {
System.out.println(streamVo);
}
// Stream流使用
streamVos.stream()
.filter(streamVo -> streamVo.getName().startsWith("小"))
.filter(streamVo -> streamVo.getName().length() == 3)
.filter(streamVo -> streamVo.getSex().equals("男"))
.forEach(System.out::println);
// 找出姓小的
List<StreamVo> toList1 = streamVos.stream().filter(streamVo -> streamVo.getName().startsWith("小")).collect(Collectors.toList());
System.out.println(toList1);
// 找出姓小的, 年龄大于30的
List<StreamVo> toList2 = streamVos.stream().filter(streamVo -> streamVo.getName().startsWith("小") && streamVo.getAge() > 30).collect(Collectors.toList());
System.out.println(toList2);
// 获取姓名的集合
List<String> toList3 = streamVos.stream().map(StreamVo::getName).collect(Collectors.toList());
System.out.println(toList3);
}
结果
[StreamVo{name='小吴', age=11, sex='女'}, StreamVo{name='小多', age=22, sex='女'}, StreamVo{name='小小强', age=33, sex='女'}, StreamVo{name='小强强', age=33, sex='男'}]
[StreamVo{name='小小强', age=33, sex='女'}, StreamVo{name='小强强', age=33, sex='男'}]
[StreamVo{name='小强强', age=33, sex='男'}]
StreamVo{name='小强强', age=33, sex='男'}
StreamVo{name='小强强', age=33, sex='男'}
[StreamVo{name='小吴', age=11, sex='女'}, StreamVo{name='小多', age=22, sex='女'}, StreamVo{name='小小强', age=33, sex='女'}, StreamVo{name='小强强', age=33, sex='男'}]
[StreamVo{name='小小强', age=33, sex='女'}, StreamVo{name='小强强', age=33, sex='男'}]
[啊吴, 啊多, 啊强, 小吴, 小多, 小小强, 小强强]
2.2 map与peek的区别
peek用来修改数据,map用来转换数据类型,peek接收一个没有返回值的λ表达式,可以做一些输出,外部处理等。map接收一个有返回值的λ表达式,之后Stream的泛型类型将转换为map参数λ表达式返回的类型。
三、函数式编程接口
特点:
1. Lambda表达式。
2.函数式编程接口的特点是只有一个抽象方法。
3.@FunctionalInterface注解。
3.1 常用的函数式编程接口
一元接口表示只有一个入参,二元接口表示有两个入参。
测试
@Test
public void test2() {
System.out.println("----------------------Function--------------------");
// Function 一个入参一个返回值
Function<String, Object> function = s -> s + "一个入参一个返回值";
Object functionResult = function.apply("Function");
System.out.println(functionResult);
System.out.println("----------------------BiFunction--------------------");
// BiFunction 两个入参一个返回值
BiFunction<String, String, String> biFunction = (s1, s2) -> s1 + s2;
String biFunctionResult = biFunction.apply("参数1", "参数2");
System.out.println(biFunctionResult);
System.out.println("----------------------Consumer--------------------");
// Consumer 一个入参没有返回值 ::方法调用 s -> System.out.println(s);
Consumer<String> consumer = System.out::println;
consumer.accept("一个入参没有返回值");
System.out.println("----------------------BiConsumer--------------------");
// BiConsumer 两个入参没有返回值
BiConsumer<String, Integer> biConsumer = (s, i) -> System.out.println("接受的参数" + s + i);
biConsumer.accept("Hello", 1);
System.out.println("----------------------Supplier--------------------");
// Supplier 无入参,一个返回值
Supplier<String> supplier = () -> "无入参,一个返回值";
String supplierResult = supplier.get();
System.out.println(supplierResult);
System.out.println("----------------------Predicate--------------------");
// Predicate一个入参,返回boolean值
Predicate<Integer> predicate = integer -> integer > 0;
boolean test1 = predicate.test(0);
boolean test2 = predicate.test(1);
System.out.println(test1);
System.out.println(test2);
System.out.println("----------------------BiPredicate--------------------");
// BiPredicate两个入参,返回boolean值
BiPredicate<String, String> biPredicate = String::equals;
boolean biPredicateResult = biPredicate.test("1", "2");
System.out.println(biPredicateResult);
System.out.println("----------------------UnaryOperator--------------------");
// UnaryOperator一个入参,一个返回值,入参类型跟返回类型一致
UnaryOperator<String> unaryOperator = s -> {
String hello = "Hello ";
return hello + s;
};
String unaryOperatorResult = unaryOperator.apply("World!");
System.out.println(unaryOperatorResult);
System.out.println("----------------------BinaryOperator--------------------");
// BinaryOperator两个入参,一个返回值,入参类型跟返回类型三个是一致的
BinaryOperator<String> binaryOperator = (s1, s2) -> s1 + s2;
String binaryOperatorResult = binaryOperator.apply("第一个入参", "第二个入参");
System.out.println(binaryOperatorResult);
}
结果
----------------------Function--------------------
Function一个入参一个返回值
----------------------BiFunction--------------------
参数1参数2
----------------------Consumer--------------------
一个入参没有返回值
----------------------BiConsumer--------------------
接受的参数Hello1
----------------------Supplier--------------------
无入参,一个返回值
----------------------Predicate--------------------
false
true
----------------------BiPredicate--------------------
false
----------------------UnaryOperator--------------------
Hello World!
----------------------BinaryOperator--------------------
第一个入参第二个入参
3.2 方法引用
正常的Lambda写法
@Test
public void test3() {
// 正常的Lambda表达式
Consumer<String> consumer1 = s -> System.out.println(s);
consumer1.accept("正常的Lambda表达式");
// 方法引用写法
Consumer<String> consumer2 = System.out::println;
consumer2.accept("方法引用写法");
}
使用方法引用比普通的Lambda表达式又简洁了一些。如果函数式接口的实现恰好可以通过调用一个方法来实现,那么我们可以使用方法引用。
方法引用又分了几种:
- 静态方法的方法引用。
- 非静态方法的方法引用。
- 构造函数的方法引用。
public class FunctionVo {
/**
* 静态方法
*/
public static void staticFunction(String value) {
System.out.println("静态方法" + value);
}
/**
* 实例方法
*/
public void instanceFunction(String value) {
System.out.println("实例方法" + value);
}
/**
* 无参构造方法
*/
public FunctionVo() {
}
/**
* 有参构造方法
*
* @param value
*/
public FunctionVo(String value) {
System.out.println(value);
}
}
@Test
public void test4() {
// 静态方法引用--通过类名调用
Consumer<String> staticFunction = FunctionVo::staticFunction;
staticFunction.accept("What!");
//实例方法引用--通过实例调用
FunctionVo functionVo = new FunctionVo();
Consumer<String> instanceFunction = functionVo::instanceFunction;
instanceFunction.accept("How!");
// 构造方法方法引用--无参数
Supplier<FunctionVo> supplier1 = FunctionVo::new;
FunctionVo functionVo1 = supplier1.get();
System.out.println(functionVo1);
// 构造方法方法引用--有参数
Consumer<String> consumer = FunctionVo::new;
consumer.accept("Dog!");
}
结果
静态方法What!
实例方法How!
com.qiang.test.FunctionVo@6073f712
Dog!
四、Date API
Clock 类提供了访问当前日期和时间的方法,Clock 是时区敏感的,可以用来取代 System.currentTimeMillis()
来获取当前的微秒数。某一个特定的时间点也可以使用 Instant
类来表示,Instant
类也可以用来创建旧版本的java.util.Date
对象。
@org.junit.Test
public void test40() {
// java8新特性Date API Clock
Clock clock = Clock.systemDefaultZone();
// 1609832443466
System.out.println("当前时间毫秒数:" + System.currentTimeMillis());
// 1609832443466
System.out.println("当前时间毫秒数:" + clock.millis());
// 2021-01-05T07:40:43.466Z
System.out.println("当前系统时间:" + clock.instant());
// Tue Jan 05 15:42:33 CST 2021
System.out.println("当前系统时间:" + Date.from(clock.instant()));
}
在新API中时区使用 ZoneId 来表示。时区可以很方便的使用静态方法of来获取到。 抽象类ZoneId
(在java.time
包中)表示一个区域标识符。 它有一个名为getAvailableZoneIds
的静态方法,它返回所有区域标识符。
@org.junit.Test
public void test41() {
// java8新特性Date API ZoneId
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
// [Asia/Aden, America/Cuiaba ...... US/Pacific, Europe/Monaco]
System.out.println("所有区域标识符" + availableZoneIds);
// ZoneRules[currentStandardOffset=+01:00]
System.out.println("获取此标识允许执行的计算的时区规则" + ZoneId.of("Europe/Monaco").getRules());
}