资讯详情

jdk8 新特性汇总

jdk8 新特性汇总

1、掌握Lambda表达式的基本用法和省略模式 2.掌握界面中使用新的静态方法和默认方法 3.掌握函数接口的用法 4.掌握方法引用的使用 5、掌握Stream集中使用流动 6、掌握JDK8对日期时间增强 7、掌握JDK8使用重复注释和类型注释 

第1章 Lambda表达式

1.1 概述

Lambda 表达式(lambda expression)是匿名函数。主要用于优化匿名内部类的结构。我们先来看看传统的匿名内部类的使用。

new Thread(new Runnable() { 
             @Override     public void run() { 
                 System.out.println("将执行一个线程。");     } }).start(); 

在这种情况下,这是一个打开线程的案例Runnable在匿名实现类中,我们只关注其中的逻辑实现System.out.println("将执行一个线程。"),但是整体代码非常繁琐和冗余。JDK8提供了Lambda表达式简化匿名内部写作,语法更简洁,如下

new Thread(()->System.out.println("将执行一个线程。")).start(); 

1.2 标准格式

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);
}

1.3 省略模式

​ 在lambda标准格式的基础上,可以使用省略写法的规则:

  • 参数类型可以省略

  • 如果参数有且仅有一个,则小括号可以省略

  • 如果方法体中有且仅有一句代码,可以同时省略大括号、return关键字以及分号。

    如常规表达式为

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

    省略模式后为

    i->i+i 
    

1.4 使用限制

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

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

1.5 常用的内置函数接口

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

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

1.5.1 Supplier接口

java.util.function.Supplier<T>接口,它表示”供给“,对应的lambda表达式需要对外提供一个符合泛型类型的对象数据。

@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);
    }
}

1.5.2 Consumer接口

java.util.function.Consumer<T> 接口用来表示“消费”一个数据,数据类型有泛型决定。

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

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

1.5.3 Function接口

java.util.function.Function<T, R> 接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件,有参数有返回。

@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"));

1.5.4 Predicate接口

java.util.function.Predicate<T> 接口用来对某种类型的数据进行判断,从而得到一个boolean类型的结果。

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

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

第2章 接口的增强

2.1 概述

​ 在JDK8以前的接口中,只能定义静态常量跟抽象方法,这对接口的扩展不太友好,比如List接口有很多实现类,当需要给List扩展一个方法时,所有实现类都必须实现这个扩展的方法,即使所有的实现都是相同的逻辑。

​ JDK8中对接口进行了增强,除了可以定义静态常量跟抽象方法外,还可以定义

2.2 默认方法

​ 接口中可以通过关键字default定义默认方法,实现类如果不想要默认方法的实现逻辑可以根据需求重新定义。

public class Demo05InterfaceEnhance { 
        

    public static void main(String[] args) { 
        
        Bird bird = new Chicken();
        bird.fly();
    }
}

interface Bird{ 
        

    default void fly(){ 
        
        System.out.println("展翅高飞");
    }

}

class Chicken implements Bird{ 
        

    @Override
    public void fly() { 
        
        System.out.println("想飞却飞不高……");
    }
}

2.3 静态方法

​ JDK8中接口还可以定义静态方法,语法如下

interface 接口名{
	修饰符 static 返回值类型 方法名(){
		方法体;
	}
}

public class Demo06InterfaceEnhance { 
        

    public static void main(String[] args) { 
        
        Swimmable.swimming();
    }
}

interface Swimmable{ 
        

    public static void swimming(){ 
        
        System.out.println("游泳");
    }
}

tips:

  • 接口中的静态方法,只能通过接口名调用,不能通过对象调用
  • 静态方法不能在实现类中重写

默认方法跟静态方法的区别

  • 默认方法通过实例调用,静态方法通过接口名调用
  • 默认方法可以被继承,实现类可以直接使用接口默认方法,也可以重写默认方法
  • 静态方法不能被继承,实现类不能重写接口的静态方法,只能通过接口名调用

第3章 方法引用

3.1 概述

是用来直接访问类或者实例的已经存在的方法或者构造方法。方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。计算时,方法引用会创建函数式接口的一个实例。

​ 当Lambda表达式中只是执行一个方法调用时,不用Lambda表达式,直接通过方法引用的形式可读性更高一些。方法引用是一种更简洁易懂的Lambda表达式。

​ 注意方法引用是一个Lambda表达式,其中方法引用的操作符是双冒号"::"。

public static void main(String[] args) { 
        
    // 选择合适的函数接口,使它拥有跟System.out对象的println方法一样的功能。
    Consumer<String> consumer = System.out::println;
    consumer.accept("斗转星移");
}

​ 方法引用分为4种:对象名引用成员方法、类名引用静态方法、类名引用实例方法、引用构造方法。

3.2 对象名引用成员方法

引用一个对象名的成员方法,语法如下

对象名::成员方法名;

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

3.3 类名引用静态方法

引用一个类名的静态方法,语法如下

类名::静态方法名;

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

3.4 类名引用实例方法

引用一个类名的实例方法,语法如下

类名::成员方法名;

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

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

3.5 引用构造方法

还可以引用一个类的构造器,语法如下

类名::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 + '\'' +
                '}';
    }
}

第4章 Stream流

4.1 概述

​ 在使用集合相关的操作中,比如过滤、匹配、遍历、排序等操作时总是需要循环来遍历所有元素,从而来得到需要的结果,但我们更关注的是实现需求的逻辑,而不是如何循环。

​ Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

​ 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);
        });

    }
}

4.2 Stream对象

java.util.stream.Stream<T> 是Java 8新加入的最常用的流接口。

获取一个流非常简单,主要有2种常用的方式:

  • 所有的 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("刘备","张飞","赵云","诸葛亮","黄忠","黄月英");

4.3 常用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不调用终结方法,中间的操作不会执行

4.3.1 forEach

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

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

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

4.3.2 count

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

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

4.3.3 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);
}

4.3.4 limit

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

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

4.3.5 skip

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

@Test
public void testStream06(){ 
        
    Stream<String 

标签: 继电器底座dtf08a

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台