JDK8新特性

Lambda表达式

Lambda 表达式(lambda expression)是一个匿名函数。主要用来优化匿名内部类的结构

匿名内部类写法:

A a = new A() {
    @Override
    public void test() {
    }
};

Lambda表达式:

不关注接口的数据类型,不关注接口的结构,只关注方法本身。

//lambda标签写法
(参数)->{
    
}

标准格式

Lambda表达式的语法为:

([参数列表]) ->{
    代码体;
}

无参的代码演示

public class Demo02Lambda {
​
    public static void main(String[] args) {
        Drinkable drinkable = ()->{
            System.out.println("大口的喝...");
        };
​
        drinkable.drink();
    }
}
​
interface Drinkable{
    void drink();
}

有参的代码演示

public class Demo03Lambda {
​
    public static void main(String[] args) {
        Eatable eatable = (food)->{
            System.out.println("大口的吃"+food);
            return "吃饱了";
        };
​
        String result = eatable.eat("牛肉");
        System.out.println(result);
​
    }
}
​
interface Eatable{
    String eat(String food);
}

省略模式

Lambda表达式省略写法

  1. 如果方法体只有一句话,则可以省略方法的花括号
  2. 如果方法形参只有一个参数,则可以省略圆括号
  3. 如果方法体只有一个return语句,则return也可以省略

如常规表达式为

(i)->{
    return i+i; 
}

省略模式后为

i->i+i 

使用限制

lambda表达式使用有几个条件需要特别注意:

  • lambda表达式是针对接口才能使用
  • 接口中必须有且仅有一个抽象方法,能被@FunctionalInterface注解修饰的方法

函数式接口

lambda表达式是针对接口的,有且仅有一个抽象方法,这种接口称为函数接口。lambda表达式使用时不关心接口名、抽象方法名,只关心抽象方法的参数列表和返回类型。因此JDK8提供了大量的常用的函数式接口。

这些函数接口都在java.util.function包下,常用接口有Supplier接口、Consumer接口、Function接口、Predicate接口。

Supplier接口

supplier表示供应商,供给的意思,这类接口的特点是:无参有返回值。

@FunctionalInterface
public interface Supplier<T> { 
    T get();
}

代码演示

public class Demo04FunctionReference {
​
    public static void main(String[] args) {
        Supplier<Integer> supplier = ()->{
          return new Random().nextInt();
        };
​
        Integer result = supplier.get();
        System.out.println("随机产生一个整数: "+result);
    }
}

Consumer接口

Consumer表示消费的意思,这类接口的特点是:有参无返回值。

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

代码演示

//      小写字符串转成大写字符串
Consumer<String> consumer = (s)->{
    System.out.println(s.toUpperCase());
};
consumer.accept("hello blb!");

Function接口

Function表示方法函数的意思 ,这类接口的特点是:有参有返回值

@FunctionalInterface
public interface Function<T, R> {
 
    R apply(T t);
}

代码演示

//       将字符串转成数字
Function<String,Integer> function = (s)->{
    return Integer.parseInt(s);
};
System.out.println(function.apply("123"));

Predicate接口

Predicate表示判定的意思,这类接口的特点是:有参有boolean类型返回值

@FunctionalInterface
public interface Predicate<T> {
 
    boolean test(T t);
}

代码演示

//      判断一个整数是否是偶数
Predicate<Integer> predicate = (i)->{
    return i%2==0;
};
System.out.println("是否是整数:"+predicate.test(18));

方法引用

方法引用是一种更简洁的lamdba表达式,如果一个lamdba表达式的方法体只是在调用一个方法时,就可以使用方法引用来简化化。

  • 对象引用实例方法
  • 类名引用静态方法
  • 类名引用实例方法
  • 引用构造方法

对象引用实例方法

对象名::方法名

代码演示

// 定义函数接口,引用System.out对象的println方法
public void testMethod1(){
    Consumer<Object> c = System.out::println;
    c.accept("bailiban");
    c.accept(123);
}

类名引用静态方法

类名::静态方法名

代码演示

// 定义函数接口,引用String类的valueOf静态方法
public void testMethod2(){
    Function<Integer, String> function = String::valueOf ;
    System.out.println(function.apply(123));
}

类名引用实例方法

类名::成员方法名

代码演示

// 定义函数接口,引用String类的length方法
public static void testMethod3(){
    Function<String,Integer> function = String::length;
    System.out.println(function.apply("bailiban"));
}

tip:String类的length方法是没有参数的,但是Function函数是有一个参数的,这个参数表示是String类的任意对象。

引用构造方法

类名::new

代码演示

// 定义函数接口,引用Student类的构造器方法
public class Demo08FunctionReference {    
​
    @Test
    public void testMethod4(){
        Function<String,Student> function = Student::new;
        Student blb = function.apply("blb");
        System.out.println(blb);
    }
​
}
​
class Student {
​
    private String name ;
​
    public Student(String name){
        this.name = name ;
    }
​
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
}

Stream流

对一个集合体做过滤、排序、统计等操作时,可以使用Stream流来简化操作。

代码演示

public class Demo09Stream {
​
    public static void main(String[] args) {
//      创建集合并添加元素
        List<String> list = new ArrayList<>();
        Collections.addAll(list,"刘备","张飞","赵云","诸葛亮","黄忠","黄月英");
//       通过流过滤姓名以“黄”开头的元素,然后遍历
        list.stream().filter((s)->{
           return s.startsWith("黄");
        }).forEach((s)->{
            System.out.println(s);
        });
​
    }
}

Stream对象的获取 

  • 所有Collection对象都有stream方法
@Test
public void testStream01(){
    //        List获取Stream
    List<String> list = new ArrayList<>();
    Stream<String> stream = list.stream();

    //        Set获取Stream
    Set<String> set = new HashSet<>();
    Stream<String> stream2 = set.stream();

    //        Map获取Stream
    Map<String, String> map = new HashMap<>();
    Stream<String> keyStream = map.keySet().stream();
    Stream<String> valueStream = map.values().stream();
    Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();
}
  •  Stream中的静态of方法
Stream<String> stringStream = Stream.of("刘备","张飞","赵云","诸葛亮","黄忠","黄月英");

Stream类的API

Stream流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:

  • 终结方法:返回值类型不再是 Stream 类型的方法,因此不再支持链式调用。主要有包括 count 和 forEach 方法。

  • 非终结方法:返回值类型仍然是 Stream 类型的方法,因此支持链式调用。

方法名

方法作用

返回值类型

方法种类

count

统计个数

long

终结

foreach

遍历

void

终结

filter

过滤

Stream

非终结

limit

限定前几个

Stream

非终结

skip

跳过前几个

Stream

非终结

map

映射

Stream

非终结

sorted

排序

Stream

非终结

distinct

去重

Stream

非终结

使用规则

  • Stream只能操作一次
  • Stream方法返回的是新的流
  • Stream不调用终结方法,中间的操作不会执行

forEach

void forEach(Consumer action)该方法接收一个 Consumer 接口函数,会将每一个流元素交给该函数进行处理。

代码演示

@Test
public void testStream02(){
    Stream<String> stream = Stream.of("刘备","张飞","赵云","诸葛亮","黄忠","黄月英");
    //        stream.forEach(s->{
    //            System.out.println(s);
    //        });

    stream.forEach(System.out::println);
}

count

long count(),Stream流提供count方法来统计其中的元素个数。

代码演示

@Test
public void testStream03(){
    Stream<String> stream = Stream.of("刘备","张飞","赵云","诸葛亮","黄忠","黄月英");
    System.out.println(stream.count());
}

filter

Stream<T> filter(Predicate<? super T> predicate)可以通过 filter 方法将一个流转换成另一个子集流。该方法将会产生一个boolean值结果,代表指定的条件是否满足。如果结果为true,那么Stream流的 filter 方法将会留用元素;如果结果为false,那么 filter 方法将会舍弃元素。

代码演示

@Test
public void testStream04(){
    Stream<String> stream = Stream.of("刘备","张飞","赵云","诸葛亮","黄忠","黄月英");
    stream.filter(s-> s.startsWith("黄")).forEach(System.out::println);
}

limit

Stream<T> limit(long maxSize) limit方法可以对流进行截取,只取用前n个。

代码演示

@Test
public void testStream05(){
    Stream<String> stream = Stream.of("刘备","张飞","赵云","诸葛亮","黄忠","黄月英");
    stream.limit(3).forEach(System.out::println);
}

skip

Stream<T> skip(long n);如果流的当前长度大于n,则跳过前n个。

代码演示

@Test
public void testStream06(){
    Stream<String> stream = Stream.of("刘备","张飞","赵云","诸葛亮","黄忠","黄月英");
    stream.skip(3).forEach(System.out::println);
}

map

<R> Stream<R> map(Function<? super T, ? extends R> mapper);如果需要将流中的元素映射到另一个流中,可以使用 map 方法。

代码演示

@Test
public void testStream07(){
    Stream<String> stream = Stream.of("1","2","3","4","5","6");
    stream.map(s->Integer.parseInt(s)).forEach(System.out::println);
}

sorted

可以需要将数据进行排序,可以使用Stream的sorted方法排序。

Stream<T> sorted();
Stream<T> sorted(Comparator<? super T> comparator);

代码演示

@Test
public void testStream08(){
    Stream<Integer> stream = Stream.of(9,4,1,2,8);
    //        stream.sorted().forEach(System.out::println);
    stream.sorted((o1,o2)->o2-o1).forEach(System.out::println);
}

distinct

如果数据需要去掉重复元素可以使用distinct方法

Stream<T> distinct();

代码演示

@Test
public void testStream09(){
    Stream<String> stream = Stream.of("刘备","张飞","赵云","诸葛亮","张飞","赵云");
    stream.distinct().forEach(System.out::println);
}

Collector

对流操作完成以后,如果需要将数据保存到数组或者集合中,可以收集流中的数据。

 <R, A> R collect(Collector<? super T, A, R> collector);

代码演示

@Test
public void testStream10(){
    Stream<String> stream = Stream.of("刘备","张飞","赵云","诸葛亮","张飞","赵云");
    //      用List集合来收集
    //        List<String> list = stream.collect(Collectors.toList());
    //      用Set集合来收集
    //        Set<String> set = stream.collect(Collectors.toSet());
    //        System.out.println(set);

    //      用ArrayList集合来收集
    ArrayList<String> arrayList = stream.collect(Collectors.toCollection(ArrayList::new));
    System.out.println(arrayList);
}

日期时间

JDK8新增了3个日期时间类,分别是:LocalDate、LocalTime、LocalDateTime

LocalDate(日期)

日期包含年月日信息,日期的操作的常用API如下

代码演示

@Test
    public void dateTime01(){
//      获取当前对应的日期
        LocalDate now = LocalDate.now();
        System.out.println(now);

        LocalDate date = LocalDate.of(2020, 12, 13);
        System.out.println(date);
//      获取年份
        System.out.println(now.getYear());
//       获取月份,英文
        System.out.println(now.getMonth());
//       获取月份值
        System.out.println(now.getMonthValue());
//        获取当月中的第几天,也就是几号
        System.out.println(now.getDayOfMonth());
//        获取当周中的第几天,也就是星期
        System.out.println(now.getDayOfWeek());
//        获取年中的第几天
        System.out.println(now.getDayOfYear());
//        修改年份为2019
        System.out.println(now.withYear(2019));
//        修改月份为2
        System.out.println(now.withMonth(2));
//        修改日期为3号
        System.out.println(now.withDayOfMonth(3));
    }

LocalTime(时间)

时间包含时分秒信息,时间操作常用的API如下

代码演示

@Test
public void dateTime02(){
    LocalTime time = LocalTime.of(11,12,13);
    System.out.println(time);
    //      获取当前时间
    LocalTime now = LocalTime.now();
    //       获取小时
    System.out.println(now.getHour());
    //       获取分
    System.out.println(now.getMinute());
    //       获取秒
    System.out.println(now.getSecond());
    //       获取纳秒
    System.out.println(now.getNano());
    //      修改小时为12
    System.out.println(now.withHour(12));
    //       修改分钟为22
    System.out.println(now.withMinute(22));
    //        修改秒为33
    System.out.println(now.withSecond(33));
}

LocalDateTime(日期时间)

日期时间包含年月日时分秒信息,常用API如下

代码演示

@Test
public void dateTime03(){
    LocalDateTime time = LocalDateTime.of(2020,12,11,10,11,12);
    System.out.println(time);

    LocalDateTime now = LocalDateTime.now();
    System.out.println(now);

    //      获取年份
    System.out.println(now.getYear());
    //       获取月份,英文
    System.out.println(now.getMonth());
    //       获取月份值
    System.out.println(now.getMonthValue());
    //        获取当月中的第几天,也就是几号
    System.out.println(now.getDayOfMonth());
    //        获取当周中的第几天,也就是星期
    System.out.println(now.getDayOfWeek());
    //        获取年中的第几天
    System.out.println(now.getDayOfYear());
    //       获取小时
    System.out.println(now.getHour());
    //       获取分
    System.out.println(now.getMinute());
    //       获取秒
    System.out.println(now.getSecond());
    //       获取纳秒
    System.out.println(now.getNano());
    //        修改年份为2019
    System.out.println(now.withYear(2019));
    //        修改月份为2
    System.out.println(now.withMonth(2));
    //        修改日期为3号
    System.out.println(now.withDayOfMonth(3));
    //      修改小时为12
    System.out.println(now.withHour(12));
    //       修改分钟为22
    System.out.println(now.withMinute(22));
    //        修改秒为33
    System.out.println(now.withSecond(33));
}

tip:

时间跟日期的修改都是返回一个新的日期时间对象,原来的日期时间对象不改变。

格式化

可以通过java.time.format.DateTimeFormatter类可以进行日期时间的解析与格式化。

代码演示

@Test
public void dateTime04(){
    //      日期转成格式化字符串
    LocalDateTime now = LocalDateTime.now();
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
    String formatNow = now.format(dtf);
    System.out.println(formatNow);

    //       格式化字符串转成日期
    LocalDateTime parse = LocalDateTime.parse("2021年01月28日 04时14分43秒", dtf);
    System.out.println(parse);
}

日期时间格式工具类

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
//System.out.println(formatter.format(localDateTime));

日期时间差

JDK8中通过Duration用于计算两个“时间”间隔。通过Period用于计算两个“日期”间隔的类。

Duration时间差

Duration代码演示

@Test
public void dateTime05(){
    LocalTime now = LocalTime.now();
    System.out.println(now);
    LocalTime time = LocalTime.of(17,48,12);
    System.out.println(time);

    Duration duration = Duration.between(now,time);
    //      时间差转成小时
    System.out.println(duration.toHours());
    //      时间差转成分钟
    System.out.println(duration.toMinutes());
    //      时间差转成秒
    System.out.println(duration.getSeconds());
    //      时间差转成纳秒
    System.out.println(duration.toNanos());

}

Period日期差

Period代码演示

@Test
public void dateTime06(){
    LocalDate now = LocalDate.now();
    LocalDate date = LocalDate.of(2030,4,30);
    Period period = Period.between(now,date);
    //      获取年份差
    System.out.println(period.getYears());
    //      获取月份差
    System.out.println(period.getMonths());
    //       获取日期差
    System.out.println(period.getDays());
}

时间校正器

有时候我们需要将日期或者时间进行校正,比如设置为“下个月的第1天”等,可以通过时间校正器进行。

  • TemporalAdjuster:时间校正器。

  • TemporalAdjusters:通过静态方法提供大量的常用的TemporalAdjuster实现。

@Test
public void dateTime07(){
    LocalDateTime now = LocalDateTime.now();
    //      设置下月1号的校正器
    TemporalAdjuster firstDayOfNextMonth = temporal -> {
        LocalDateTime time = (LocalDateTime) temporal;
        return time.plusMonths(1).withDayOfMonth(1);
    };
    //      通过校正器调节now的值
    System.out.println(now.with(firstDayOfNextMonth));
​
    //       TemporalAdjusters获取下一年的第1天的校正器
    System.out.println(now.with(TemporalAdjusters.firstDayOfNextYear()));
​
}

 

//6、获取这个月的最后1天(超纲)
//      LocalDate now = LocalDate.of(2022, 2, 1);
//      LocalDate localDate = now.with(TemporalAdjusters.lastDayOfMonth());
//      System.out.println(localDate);
​
//7、获取下个月的最后1天(超纲)
LocalDate localDate = LocalDate.now().plusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
System.out.println(localDate);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力学习Java的鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值