1、Lambda 表达式
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
//输出Hello shawn
@Test
void test12(){
// 用括号
GreetingService greetService = (message) ->
System.out.println("Hello " + message);
greetService.sayMessage("shawn");
}
interface GreetingService {
void sayMessage(String message);
}
2、函数式接口
函数接口是只有一个抽象方法的接口,用作 Lambda 表达式的类型。使用@FunctionalInterface注解修饰的类,编译器会检测该类是否只有一个抽象方法或接口,否则,会报错。可以有多个默认方法,静态方法。
函数接口 | 抽象接口 | 功能 | 参数 | 返回类型 |
---|---|---|---|---|
Predicate | test(T t) | 判断真假 | T | boolean |
Consumer | accept(T t) | 消费消息 | T | void |
Function | R apply(T t) | 将T映射为R | T | R |
Supplier | T get() | 生产消息 | None | T |
UnaryOperator | T apply(T t) | 一元操作 | T | T |
BinaryOperator | apply(T t,U u) | 二元操作 | (T,U) | T |
常用的方法举例
@SpringBootTest
public class Java8FunctionalTests {
@Test
void test01(){
Predicate<Integer> predicate = x -> x > 170;
Student student = new Student("shawn", 175);
System.out.println("shawn的身高有超过170吗?" + predicate.test(student.getHeight()));
Consumer<String> consumer = System.out::println;
consumer.accept("我命由我不命天");
//Student映射成String
Function<Student, String> function = Student::getName;
String name = function.apply(student);
System.out.println(name);
Supplier<Integer> supplier =
() -> Integer.valueOf(BigDecimal.TEN.toString());
System.out.println(supplier.get());
UnaryOperator<Boolean> unaryOperator = flag -> !flag;
Boolean apply2 = unaryOperator.apply(true);
System.out.println(apply2);
BinaryOperator<Integer> operator = (x, y) -> x * y;
Integer integer = operator.apply(2, 3);
System.out.println(integer);
test(() -> "我是一个演示的函数式接口");
}
/**
* 演示自定义函数式接口使用
*
* @param worker
*/
public static void test(Worker worker) {
String work = worker.work();
System.out.println(work);
}
@FunctionalInterface
public interface Worker {
String work();
}
}
另一种使用就是可以消除大量if-else,给代码解耦合,这里我简单贴部分demo
// 里面可以分几个类,这里我全写在一起了
public class MainTest {
public static void main(String[] args) {
// 这里相当于进行了if else操作了,代码更加简洁
// 有内容输出内容,没有内容输出空字符串
isBlankOrNoBlank("hello world")
.presentOrElseHandle(System.out::println,()->{
System.out.println("空字符串");
});
}
/**
* 空值与非空值分支处理
*/
@FunctionalInterface
public interface BranchHandle<T extends Object> {
/**
* if else两种处理函数
* <? extends T> 表示类型的上界,表示参数化类型的可能是T 或是 T的子类;
* <? super T> 表示类型下界(Java Core中叫超类型限定),表示参数化类型是此类型的超类型(父类型),直至Object;
*/
void presentOrElseHandle(Consumer<? super T> action, Runnable emptyAction);
}
/**
* 参数为true或false时,分别进行不同的操作
**/
public static BranchHandle<?> isBlankOrNoBlank(String str){
return (consumer, runnable) -> {
if (str == null || str.length() == 0){
runnable.run();
} else {
consumer.accept(str);
}
};
}
}
3、Stream流式编程
Stream(流)是一个来自数据源的元素队列并支持聚合操作
- 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
- 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
- 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
1. collect(Collectors.toList())
将流转换为list。还有toSet(),toMap()等。及早求值。
@Test
void test01(){
List<Student> studentList = Stream.of(
new Student("shawn",165),
new Student("shawn22",170))
.collect(Collectors.toList());
System.out.println(studentList);
}
//[Student(name=shawn, height=165), Student(name=shawn22, height=170)]
2. forEach
Stream 提供了新的方法 forEach
来迭代流中的每个数据
@Test
void test02(){
Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);
}
3. filter
过滤筛选的作用。内部就是Predicate接口。惰性求值。
@Test
void test03(){
List<Student> studentList = Stream.of(
new Student("shawn",165),
new Student("shawn22",170))
.filter(s -> s.getHeight()>165)
.collect(Collectors.toList());
System.out.println(studentList);
}
//[Student(name=shawn22, height=170)]
3. map
转换功能,内部就是Function接口。惰性求值
@Test
void test04(){
List<String> studentList = Stream.of(
new Student("shawn",165),
new Student("shawn22",170))
.filter(s -> s.getHeight() > 165)
.map(s-> s.getName())
.collect(Collectors.toList());
System.out.println(studentList);
}
//[shawn22]
5. flatMap
将多个Stream合并为一个Stream。惰性求值
@Test
void test05(){
List<Student> studentList = Arrays.asList(
new Student("shawn",165),
new Student("shawn22",170));
Stream.of(studentList, Collections.singletonList(
new Student("shawn222", 180)))
.flatMap(Collection::stream)
.map(s->s.getName())
.forEach(System.out::println);
}
//shawn
//shawn22
//shawn222
6. max和min
集合中求最大值和最小值,及早求值。maxBy或者minBy就是求最大值与最小值。
@Test
void test06(){
List<Student> studentList = Arrays.asList(
new Student("shawn",165),
new Student("shawn22",170));
Optional<Student> student = studentList.stream()
.min(Comparator.comparing(Student::getHeight));
if(student.isPresent()){
System.out.println(student.get());
}
}
//Student(name=shawn, height=165)
7. count
统计功能,一般都是结合filter使用,因为先筛选出我们需要的再统计即可。及早求值
@Test
void test07(){
List<Student> studentList = Arrays.asList(
new Student("shawn",165),
new Student("shawn22",170));
long count = studentList.stream().filter(s -> s.getHeight() > 165).count();
System.out.println(count);
}
//1
8. reduce
reduce 操作可以实现从一组值中生成一个值
@Test
void test08(){
System.out.println(Stream.of(1, 2, 3, 4, 5).reduce(10, Integer::sum));
}
//25
9. collect高级用法
//将分成true和false两个集合
@Test
void test09(){
List<Student> studentList = Arrays.asList(
new Student("shawn",165),
new Student("shawn22",170));
System.out.println(studentList.stream()
.collect(Collectors.partitioningBy(s -> s.getName().contains("shawn"))));
}
//{false=[], true=[Student(name=shawn, height=165), Student(name=shawn22, height=170)]}
//Collectors.groupingBy与SQL 中的 group by 操作是一样的。
@Test
void test010(){
List<Student> studentList = Arrays.asList(
new Student("shawn",165),
new Student("shawn22",170));
System.out.println(studentList.stream()
.collect(Collectors.groupingBy(Student::getName)));
}
//字符串拼接
@Test
void test011(){
List<Student> studentList = Arrays.asList(
new Student("shawn",165),
new Student("shawn22",170));
System.out.println(studentList.stream().map(Student::getName)
.collect(Collectors.joining(",","[","]")));
}
//[shawn,shawn22]
4、Optional类
Optional 类是一个可以为null的容器对象。目的是为了解决空指针异常。
1. empty()
返回一个Optional
容器对象,而不是 null。建议常用⭐⭐⭐⭐
2. get()
如果创建的Optional中有值存在,则返回此值,否则抛出NoSuchElementException
。在判空之前,千万不要直接使用!尽量别用!⭐
//会报错java.util.NoSuchElementException: No value present
@Test
void test01(){
Optional<User> opt = Optional.empty();
System.out.println(opt.get());
}
3. of(T value)
创建一个Optional
对象,如果 value 是 null,则抛出 NPE。不建议用⭐⭐
4. ofNullable(T value)
同上,创建一个Optional
对象,但 value 为空时返回Optional.empty()
。推荐使用⭐⭐⭐⭐⭐
@Test
void test02(){
User user = null;
//输出Optional.empty,若存在就输出值
System.out.println(Optional.ofNullable(user));
//会报错java.lang.NullPointerException
System.out.println(Optional.of(user));
}
5. orElse(T other)
同样是返回Optional
中包装的值,但不同的是当取不到值时,返回你指定的 default。可以用⭐⭐⭐
6. orElseGet(Supplier<? extends T> other)
如果创建的Optional中有值存在,则返回此值,否则返回一个由Supplier接口生成的值。推荐使用⭐⭐⭐⭐⭐
private User createNewUser() {
System.out.println("user方法创建");
return new User("shawn", "男");
}
@Test
public void test03() {
User user = null;
//下面两个若是空,都会调用本地方法创建新的,但是orElse无论是否存在值,都会执行方法,另一个却不会
User result = Optional.ofNullable(user).orElse(createNewUser());
User result2 = Optional.ofNullable(user).orElseGet(this::createNewUser);
System.out.println(result);
System.out.println(result2);
}
/*结果显示
user方法创建
user方法创建
User(name=shawn, sex=男)
User(name=shawn, sex=男)
*/
7. orElseThrow(Supplier<? extends X> exceptionSupplier)
如果创建的Optional中有值存在,则返回此值,否则抛出一个由指定的Supplier接口生成的异常。阻塞性业务场景推荐使用⭐⭐⭐⭐
@Test
public void test04() {
User user = null;
User result = Optional.ofNullable(user).orElseThrow(NullPointerException::new);
}
//输出java.lang.NullPointerException
8. isPresent()
如果创建的Optional中的值存在,返回true,否则返回false。在某些情况下很有用,但尽量不要用在 if 判断体中。可以用⭐⭐⭐
9. ifPresent(Consumer<? super T> consumer)
判断Optional
中是否有值,有值则执行 consumer,否则什么都不干。日常情况下请使用这个⭐⭐⭐⭐
10. filter(Predicate<? super T> predicate)
如果创建的Optional中的值满足filter中的条件,则返回包含该值的Optional对象,否则返回一个空的Optional对象
11. map
如果创建的Optional中的值存在,对该值执行提供的Function函数调用
@Test
public void test05() {
User user = new User("shawn", "男");
String sex = Optional.ofNullable(user)
.map(User::getSex).orElse("女");
System.out.println(sex);
}
//输出男
12. flagMap
如果创建的Optional中的值存在,就对该值执行提供的Function函数调用,返回一个Optional类型的值,否则就返回一个空的Optional对象,其返回的值是解除包装的值
//该方法在User类中定义
public Optional<String> getPosition() {
return Optional.ofNullable(name);
}
@Test
public void test06() {
User user = new User("shawn", "男");
String sex = Optional.ofNullable(user)
.flatMap(User::getPosition).orElse("女");
System.out.println(sex);
}
//输出男
13. filter
filter() 接受一个 Predicate 参数,返回测试结果为 true 的值。如果测试结果为 false,会返回一个空的 Optional。
@Test
public void test07() {
User user = new User("shawn", "男");
Optional<User> result = Optional.ofNullable(user)
.filter(u -> u.getName() != null && u.getSex().contains("女"));
System.out.println(result);
}
//返回Optional.empty
14. 其他
Java 9 为 Optional 类添加了三个方法:or()、ifPresentOrElse() 和 stream()。or() 方法与 orElse() 和 orElseGet() 类似,它们都在对象为空的时候提供了替代情况。or() 的返回值是由 Supplier 参数产生的另一个 Optional 对象。
5、Base64
Base64工具类提供了一套静态方法获取下面三种BASE64编解码器:
- **基本:**输出被映射到一组字符A-Za-z0-9+/,编码不添加任何行标,输出的解码仅支持A-Za-z0-9+/。
- **URL:**输出映射到一组字符A-Za-z0-9+_,输出是URL和文件。
- **MIME:**输出隐射到MIME友好格式。输出每行不超过76字符,并且使用’\r’并跟随’\n’作为分割。编码输出最后没有行分割。
@Test
void test01() throws Exception {
// 编码
String B64 = Base64.getEncoder().encodeToString("hello?world".getBytes(StandardCharsets.UTF_8));
System.out.println(B64); // 输出为: aGVsbG8/d29ybGQ=
// 解码
byte[] baseBytes = Base64.getDecoder().decode("aGVsbG8/d29ybGQ=");
System.out.println(new String(baseBytes, StandardCharsets.UTF_8)); // 输出为: hello?world
String urlB64 = Base64.getUrlEncoder().encodeToString("hello?world".getBytes(StandardCharsets.UTF_8));
System.out.println(urlB64); // 输出为: aGVsbG8_d29ybGQ=
String mineB64 = Base64.getMimeEncoder().encodeToString("hello?world".getBytes(StandardCharsets.UTF_8));
System.out.println(mineB64); // 输出为: aGVsbG8/d29ybGQ=
}
6、Java 8 日期时间
新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作。
@Test
void test(){
// 获取当前的日期时间
LocalDateTime currentTime = LocalDateTime.now();
//当前时间: 2021-08-05T12:06:15.590185
System.out.println("当前时间: " + currentTime);
LocalDate date1 = currentTime.toLocalDate();
//当前日期: 2021-08-05
System.out.println("当前日期: " + date1);
Month month = currentTime.getMonth();
int month1 = currentTime.get(ChronoField.MONTH_OF_YEAR);
int day = currentTime.getDayOfMonth();
int seconds = currentTime.getSecond();
//月: 8, 日: 5, 秒: 15
System.out.println("月: " + month1 +", 日: " + day +", 秒: " + seconds);
LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2022);
//date2: 2022-08-10T12:06:15.590185
System.out.println("date2: " + date2);
LocalDate date3 = LocalDate.of(2022, Month.DECEMBER, 12);
//date3: 2022-12-12
System.out.println("date3: " + date3);
LocalTime date4 = LocalTime.of(22, 15);
//date4: 22:15
System.out.println("date4: " + date4);
// 解析字符串
LocalTime date5 = LocalTime.parse("20:15:30");
//date5: 20:15:30
System.out.println("date5: " + date5);
Instant instant = Instant.now();
long currentMilli = instant.toEpochMilli();
//当前毫秒数:1628136375597
System.out.println("当前毫秒数:"+currentMilli);
// 获取当前时间日期
ZonedDateTime date6 = ZonedDateTime.parse("2015-12-03T10:15:30+05:30[Asia/Shanghai]");
//date6: 2021-08-05
System.out.println("date6: " + date1);
ZoneId id = ZoneId.of("Europe/Paris");
//ZoneId: Europe/Paris
System.out.println("ZoneId: " + id);
ZoneId currentZone = ZoneId.systemDefault();
//当期时区: Asia/Shanghai
System.out.println("当期时区: " + currentZone);
}
参考文章:
https://www.matools.com/api/java8
https://www.runoob.com/java/java8-new-features.html
https://mp.weixin.qq.com/s/8n_3VaAcwauGHgoSG1K14g