Java8新特性

写在前面:

记得有次面试。问道Java8新特性知道吗?Lambda用过吗?。灰溜溜的回答道。“没…”

现在公司普遍都是jdk1.8了,里面补充了很多新的语法新的类。Lambda和Stream尤为明显。之前看到腾哥,使用Stream流操作集合,那熟练度。正好用时下热门梗“小朋友,你是否有很多问号?”。当下jdk1.8也比较稳定,使用者占据了大多数。尽管后面java9,10都上了。但还是要遵循万物逐步演进的过程。先把当下已经稳定了的1.8学起来。后面的,可能还不是主流。会了1.8后面的也可以照猫画虎慢慢探索。话不多说,开始吧。

老样子。尚硅谷。B站。看视频。跟着敲。做笔记。做总结。

百度网盘资料:

B站地址https://www.bilibili.com/video/av62117143?p=21
百度网盘链接https://pan.baidu.com/s/1bpk5TmA2ZQ2XAYU4vydQng 
提取码0axc

主要目录

1. Lambda 表达式

2. 函数式接口

3. 方法引用与构造器引用

4. Stream API

5. 接口中的默认方法与静态方法

6. 新时间日期 API 7. 其他新特性


一、Lambda 表达式

Comparator和Comparable有什么区别?

①前者是java.util包。后者java.lang包

②Comparator不用修改源代码,但专门要实现一个比较器

Class UserComparator implements Comparator<User>{
  @Overrde
    Public int compare(User u1,User u2){
      Return Integer.compare(u1.getAge(),u2.getAge());
  }
}

业务代码一般通过Comparator内部类排序

Collections.sort(list,new Comparator<User>{
    @Override
    Public int compare(User u1,User u2){
      Retun ….
    }
});

③Comparable对代码有入侵性,破坏原子类。需要实现comparto方法

什么是Lambda?

Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。

//原来匿名内部类生成
@Test
public void test1(){
    Comparator<Integer> comparator = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return Integer.compare(o1,o2);
        }
    };
}
//lambad表达式
@Test
public void test2(){
    Comparator<Integer> comparator = (x,y)->Integer.compare(x,y);
}

Lambda 操作符

Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “->”

它将 Lambda 分为两个部分:

左侧:指定了 Lambda 表达式需要的所有参数

右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能。

Lambda 表达式语法

//无参 无返回值
@Test
public void test1(){
    int num = 0;//jdk1.7前 必须要加final jdk1.8后可以不加final


    Runnable r1 = new Runnable() {
        @Override
        public void run() {
            System.out.println("hello"+num);
        }
    };
    r1.run();
    System.out.println("===========================");
    Runnable r2 = () -> System.out.println("world");
    r2.run();
}
//有参 无返回值
//若只有一个参数 ()可省略
@Test
public void test2(){
    Consumer consumer = (e) -> System.out.println(e);
    consumer.accept(1);
}
//有多个参数 有返回值 且lambda体中有多条语句 加{}
                    //lambda体只有一条语句 可省略return和{}
@Test
public void test3(){
    Comparator<Integer> comparator = (x,y)->{
        System.out.println("lambda函数式接口");
        return Integer.compare(x,y);
    };
    System.out.println(comparator.compare(10,5));


    Comparator<Integer> comparator1 = (x,y)->Integer.compare(x,y);
    System.out.println(comparator1.compare(10,20));
}

类型推断

Lambda表达式参数列表的数据类型可以省略不写,因为JVM编译器,通过上下文推断出数据类型。

二、函数式接口

什么是函数式接口?

接口中只有一个抽象方法的接口。

可以使用@FunctionalInterface修饰。

//自定义函数式接口
@FunctionalInterface
public interface MyFilter {
    public (abstract) Integer filter(Integer integer);
}
//作为参数传递 Lambda 表达式
public Integer operation(Integer num,MyFilter myFilter){
    return myFilter.filter(num);
}
//函数式接口
@Test
public void test(){
    Integer flag = operation(101,(e) -> e*e);
    System.out.println(flag);
//        Integer num = operation(88, new MyFilter() {
//            @Override
//            public Integer filter(Integer integer) {
//                return integer*integer;
//            }
//        });
//        System.out.println(num);
}

Java 内置四大核心函数式接口

Consumer<T>消费型接口
  void accept(T t)
@Test
public void test1(){
    happy(1.1,(e)-> System.out.println("消费"+e));
}
public void happy(double money,Consumer<Double> consumer){
     consumer.accept(money);
}
Supplier 供给型接口
  T get() 
//供给型接口 Supplier<T>
@Test
public void test2(){
    List<Integer> list = getValue(10,() -> (int)(Math.random()*100));
    for (Integer integer : list) {
        System.out.println(integer);
    }
}
//产生指定个数的随机数
public List<Integer> getValue(Integer num,Supplier<Integer> supplier){
    List<Integer> list = new ArrayList<>();
    for (int i = 0; i <= num ; i++) {
        list.add(supplier.get());
    }
    return list;
}
Function<T,R>函数型接口
  Apply(T t)
//函数型接口 Function<T,R>
@Test
public void test3(){
    String s = strHandler(" qweasdzx c ", (t) -> t.trim().toUpperCase());
    System.out.println(s);
}
public String strHandler(String str,Function<String,String> function){
    return function.apply(str);
}
Predicate<T>断言型接口
  Boolean test(T t)
@Test
public void test4(){
    boolean predicate = predicate(100, (num) -> num >= 99 ? true : false);
    System.out.println(predicate);
}
public boolean predicate(int num,Predicate<Integer> predicate){
    return predicate.test(num);
}

三、方法引用与构造器引用

方法引用:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!

使用操作符 “::” 将方法名和对象或类的名字分隔开来。

(实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!)

如下三种主要使用情况:

对象::实例方法名

类::静态方法名

类::实例方法名

方法引用

//对象::实例方法名
@Test
public void test1(){
    PrintStream ps = System.out;
    Consumer<String> consumer = ps::println;


    Consumer<String> consumer1 =(e) -> ps.println(e);
    consumer1.accept("q");
}
//类::静态方法名
@Test
public void test3(){
    Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);
    System.out.println(comparator.compare(10,5));;


    Comparator<Integer> comparator1 = Integer::compare;
    System.out.println(comparator1.compare(10,20));
}

注意:当需要引用方法的第一个参数是调用对象,并且第二个参数是需要引用方法的第二个参数(或无参数)时:ClassName::methodName

构造器引用

//构造器引用 ClassName::new
@Test
public void test5(){
    Supplier<Employee> supplier = () -> new Employee();
    System.out.println(supplier.get());


    Supplier<Employee> supplier1 = Employee::new;
    System.out.println(supplier1.get());
}

数组引用

//数组引用 Type[]::new
@Test
public void test6(){
    Function<Integer,String[]> function1 = (num) -> new String[num];
    String[] strings = function1.apply(10);
    System.out.println(strings.length);


    Function<Integer,String[]> function2 = String[]::new;
    String[] strings1 = function2.apply(20);
    System.out.println(strings1.length);
}


四、Stream API

什么是Stream?

Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL执行的数据库查询。也可以使用 Stream API 来并行执行操作。

注意:

①Stream 自己不会存储元素。

②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

Stream 的操作三个步骤

创建 Stream

创建Stream流的几种方式?

①Collection提供的stream()、paralleStream()并行

②Arrays.stream(数组)

③Stream.of("a", "b","c")

无限流

//迭代

       Stream<Integer> stream4 = Stream.iterate(0,(e)->e*2);

//生成

       Stream<Integer> generate = Stream.generate(() -> (int)(Math.random()*100));

中间操作

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!

(筛选与切片)

方 法

描 述

filter(Predicate p)

接收 Lambda , 从流中排除某些元素。

distinct()

筛选,通过流所生成元素的 hashCode() 和 equals() 去 除重复元素

limit(long maxSize)

截断流,使其元素不超过给定数量。

skip(long n)

跳过元素,返回一个扔掉了前 n 个元素的流。

(映射)

方 法

描 述

map(Function f)

接收一个函数\lambda作为参数,该函数会被应用到每个元素。

flatMap(Function f)

一对多,可以操作对象里的对象。

add和addAll有什么区别?

List<String> list = Arrays.asList("aaa","bbb","ccc","ddd","eee");
List list1 = new ArrayList();
List list2 = new ArrayList();
list1.add(list);
for (Object o : list1) {
    System.out.print(o);
}
System.out.println("");
list2.addAll(list);
for (Object o : list2) {
    System.out.print(o);
}


[aaa, bbb, ccc, ddd, eee]
aaabbbcccdddeee
addAll添加的是每个元素

(排序)

方 法

描 述

sorted()

产生一个新流,其中按自然顺序排序

sorted(Comparator  comp)

产生一个新流,其中按比较器顺序排序

@Test
public void test3(){
    employees.stream()
             .sorted((x,y)->Integer.compare(x.getAge(),y.getAge()))
             .forEach(System.out::println);
}

终止操作

方 法

描 述

allMatch(Predicate p)

检查是否匹配所有元素

anyMatch(Predicate p)

检查是否至少匹配一个元素

noneMatch(Predicate p)

检查是否没有匹配所有元素

findFirst ()

返回第一个元素

findAny()

返回当前流中的任意元素

count()

返回流中元素总数

max(Comparator c)

返回流中最大值

min(Comparator c)

返回流中最小值

forEach(Consumer c)

内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了)

归约

可以将流中元素反复结合起来,得到一个值。返回 Optional

@Test
public void test2(){
    Optional<Double> reduce = employees.stream()
            .map(Employee::getSalary)
            .reduce(Double::sum);
    System.out.println(reduce.get());
}

备注:map 和 reduce 的连接通常称为 map-reduce 模式,因 Google 用它 来进行网络搜索而出名。

收集

方 法

描 述

collect(Collector c)

将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法

@Test
public void test3(){
    //转换成HashSet Collectors.toCollection(HashSet::new)
    HashSet<String> collect = employees.stream()
            .map(Employee::getName)
            .collect(Collectors.toCollection(HashSet::new));
    collect.forEach((e)-> System.out.println(e));
    //求平均值 Collectors.averagingDouble((e) -> e.getSalary())
    Double collect1 = employees.stream()
            .collect(Collectors.averagingDouble((e) -> e.getSalary()));
    System.out.println(collect1);
    //求和 Collectors.summingDouble(Employee::getSalary)
    Double collect2 = employees.stream()
            .collect(Collectors.summingDouble(Employee::getSalary));
    System.out.println(collect2);
    //最大值
    Optional<Employee> collect3 = employees.stream()
            .collect(Collectors.maxBy((x,y)->Double.compare(x.getSalary(),y.getSalary())));
    System.out.println(collect3.get());
    //最小值
    Optional<Employee> collect4 = employees.stream()
            .collect(Collectors.minBy((x, y) -> Double.compare(x.getSalary(), y.getSalary())));
    System.out.println(collect4.get());


    Optional<Double> collect5 = employees.stream()
            .map(Employee::getSalary)
            .collect(Collectors.minBy((x, y) -> Double.compare(x, y)));
    System.out.println(collect5.get());
}

并行流与串行流

并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。

Stream API 可以声明性地通过 parallel() 与sequential()在并行流与顺序流之间进行切换。


五、接口中的默认方法与静态方法

①Java8接口中允许有方法实现。也包括允许有静态方法实现。

public interface Interface1 {
    default String getName(){
        return "Interface1";
    }
    public static void show(){
        System.out.println("java8接口中允许带有静态方法");
    }
}
public interface Interface2 {
    default String getName(){
        return "Interface2";
    }
}

②接口默认方法的”类优先”原则。当继承某个类和实现了某个接口,它们的方法名和参数列表都一样时,优先加载继承类的方法

public class Class1 {
    public String getName(){
        return "Class1";
    }
}
public interface Interface1 {
    default String getName(){
        return "Interface1";
    }
    public static void show(){
        System.out.println("java8接口中允许带有静态方法");
    }
}
public class Impl extends Class1 implements Interface1 {
}
public class Main {
    public static void main(String[] args) {
        Impl impl = new Impl();
        System.out.println(impl.getName());
    }
}

③当实现了多个接口,且接口中同名同参时,必须重写该方法

六、新时间API

Date

LocalDate、LocalTime、LocalDateTime

LocalDate、LocalTime、LocalDateTime 类的实例是不可变(线程安全)的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。

@Test
public void test1(){
    LocalDateTime ldf = LocalDateTime.now();
    //加1000年
    LocalDateTime plusYears = ldf.plusYears(1000);
    //加20天
    LocalDateTime minusDays = ldf.minusDays(20);
    //指定日期
    LocalDateTime ldf2 = LocalDateTime.of(1111,11,11,11,11,11);
    System.out.println(ldf2.getYear());
    System.out.println(ldf2.getMonthValue());
    System.out.println(ldf2.getDayOfMonth());
    System.out.println(ldf2.getHour());
    System.out.println(ldf2.getMinute());
}

Instant 时间戳

用于“时间戳”的运算。它是以Unix元年(传统的设定为UTC时区1970年1月1日午夜时分)开始所经历的描述进行运算。

@Test
public void test2(){
    Instant instant = Instant.now();
    System.out.println(instant);
    //时区偏移量 +8小时
    OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
    System.out.println(offsetDateTime);
    //转换为时间戳
    long l = instant.toEpochMilli();
    System.out.println(l);
    //加10秒
    Instant instant1 = Instant.ofEpochSecond(10);
    System.out.println(instant1);
}

Duration

用于计算两个“时间”间隔

@Test
public void test3() throws InterruptedException {
    Instant instant = Instant.now();
    Thread.sleep(1000);
    Instant instant1 = Instant.now();
    System.out.println(Duration.between(instant,instant1).toMillis());
}

Period

用于计算两个“日期”间隔

@Test
public void test4(){
    LocalDate ld1 = LocalDate.of(1998,10,17);
    LocalDate ld2 = LocalDate.now();
    System.out.println(Period.between(ld1,ld2).getYears());
    System.out.println(Period.between(ld1,ld2).getMonths());
    System.out.println(Period.between(ld1,ld2).getDays());
}

时间校正器

LocalDate localDate = LocalDate.now()
    .with(TemporalAdjusters.next(DayOfWeek.MONDAY));
System.out.println(localDate);
TemporalAdjusters : 该类通过静态方法提供了
大量的常用 TemporalAdjuster 的实现。

解析与格式化

java.time.format.DateTimeFormatter

@Test
public void test6(){
    //预定义的标准格式
    DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE;
    LocalDate localDate = LocalDate.now();


    String format = localDate.format(dtf);
    System.out.println(format);
    //自定义的格式
    DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    String format1 = localDate.format(dtf2);
    LocalDate parse = LocalDate.parse("1111-12-10", dtf2);
}

时区的处理

ZonedDate、ZonedTime、ZonedDateTime
@Test
public void test7(){
    //获得所有时区
    Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
    //availableZoneIds.forEach(System.out::println);
    //.now(ZoneId.of("{区域}/{城市}"))
    LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    String str = localDateTime.format(dtf);
    System.out.println(str);
    //.atZone()指定某个“{区域}/{城市}”
    ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Asia/Tokyo"));
    System.out.println(zonedDateTime);
}

七、其他新特性

Optional 类

Optional类(java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用null 表示一个值不存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常。

Optional.of(T t) :

创建一个 Optional 实例

Optional.ofNullable(T t):

允许传入Null

isPresent() :

相当于!=null

orElse(T t) :

若为空,则输出T。不为空,照常输出。

map(Function f):

如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()

flatMap(Function mapper)

与 map 类似,要求返回值必须是Optional

@Test
public void test5(){
    Optional<Employee> optional = Optional.ofNullable(new Employee(228, "张三", 8500.0, Employee.Status.BUSY.getName()));
    //Optional<String> s = optional.map(Employee::getName);
    //System.out.println(s);
    Optional<Employee> employee = optional.flatMap((e) -> Optional.of(new Employee(28, "张三", 8500.0, Employee.Status.BUSY.getName())));
    System.out.println(employee.get());
}

重复注解与类型注解

Java 8对注解处理提供了两点改进:可重复的注解及可用于类型的注解。

//可重复的
@Repeatable(MyAnnotaions.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotaion {
    String value1() default "atguigu";
}


@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotaions {
    MyAnnotaion[] value();
}


public class TestAnnotaion {


    @MyAnnotaion(value1="hello")
    @MyAnnotaion(value1="world")
    @MyAnnotaion()
    public void show(@MyAnnotaion(value1 = "wowowo") String string){
        System.out.println("string" + string);
    }


    @Test
    public void test1() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
        Class<TestAnnotaion> c = TestAnnotaion.class;
        Method method = c.getMethod("show",String.class);


        TestAnnotaion testAnnotaion = c.newInstance();
        method.invoke(testAnnotaion,"aaa");


        MyAnnotaion[] annotationsByType = method.getAnnotationsByType(MyAnnotaion.class);


        for (MyAnnotaion myAnnotaion : annotationsByType) {
            System.out.println(myAnnotaion.value1());
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值