java8常用新特性

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注解修饰的类,编译器会检测该类是否只有一个抽象方法或接口,否则,会报错。可以有多个默认方法,静态方法。

函数接口抽象接口功能参数返回类型
Predicatetest(T t)判断真假Tboolean
Consumeraccept(T t)消费消息Tvoid
FunctionR apply(T t)将T映射为RTR
SupplierT get()生产消息NoneT
UnaryOperatorT apply(T t)一元操作TT
BinaryOperatorapply(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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值