JDK8的一些新特性

本文介绍了JDK8的重要新特性,包括lambda表达式、方法引用、默认方法、函数式接口及Stream流操作等内容。通过实例展示了如何使用这些新特性提高编程效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JDK8的一些新特性整理、最近一直在看关于spring boot 和spring cloud的一些知识、

JDK8的一个明显的新特点就是lambda表达式。

一、lambda 表达式

学习过c/c++的应该对lambda不陌生、java中的lambda的形式一般为

(parameters) -> expression
或
(parameters) ->{statements; }

第一个()内的是lambda捕获的参数、而在->的部分是在lambda表达式的执行部分,可以理解成一个匿名的方法。

lambda的实例

创建两个接口

public interface MathOperation {
    int operation(int a ,int b);
}
public interface GreetingService {
    void sayMessage(String message);
}
public static void main(String[] args) {
        LambdaTest lambdaTest = new LambdaTest();

        //添加了类型声明
        MathOperation addition = (int a,int b)->a+b;
        //没有类型声明
        MathOperation subtraction =(a,b)->a-b;
        //大括号内的返回语句
        MathOperation multi = (a,b)->(a*b);
        //不在大括号内的返回语句
        MathOperation div = (a,b)->a/b;

        System.out.println("10 + 5 = "+lambdaTest.operator(10,5, addition ));
        System.out.println("10 - 5 = "+lambdaTest.operator(10,5, subtraction ));
        System.out.println("10 * 5 = "+lambdaTest.operator(10,5, multi ));
        System.out.println("10 / 5 = "+lambdaTest.operator(10,5, div ));


//        在GreetingService添加方法mean(String s) ,void mean(String s,String t);会报错啊
//        看来在interface中的接口只能有一个
        GreetingService greetingService = (s)->System.out.println(s);
        greetingService.sayMessage( "hello" );

        GreetingService greetingService2 = (message) -> System.out.println(salutation+message);
        greetingService2.sayMessage( "david" );

    }
    private int operator(int a,int b,MathOperation mathOperation){
        return mathOperation.operation(a,b);
    }

从这个例子中可以看到lamdba定义了接口中执行的方法、而且lambda提供的方法接口不需要再创建匿名类,提升了java的编程效率。

public interface MathOperation {
    int operation(int a ,int b);

    int operation2(int a );

    int operatione(int a,int b);
}

如果把接口添加方法、程序会报错no-overrding abstract methods found

需要注意的是又lambda提供接口方法的接口中只能有一个方法、无论在接口中添加接口方法参数是否改变、程序依然会报错.

还一个需要注意的地方是被lambda表达式引用的对象,需要是最终变量或是实际上的不被后面程序修改的最终变量

如:

public interface Converter<T1,T2> {
    void convert(int i);
}
public class LambdaTest2 {

    public static void main(String[] args) {
        int num = 1;
//        Converter<Integer,String> converter=(n,s)-> System.out.println((n+num)+s);
//        converter.convert( 3,"add" );
        Converter<Integer,String> converter = (n)->System.out.println(String.valueOf(n + num));
        converter.convert( 3 );
//        num=6;  lambda所引用的变量必须为最终变量或实际上的最终的变量
    }
}

如果不将num=6注释掉的话、运行时会报错,因为num被lambda表达式下方的程序修改了。

public static void main(String[] args) {
        String first = "";
        Compare<Integer> compare = (first,second) ->     
        System.out.println((Integer.compare( first.length(),second.length() )));
        compare.com( "abc","def" );
}

当然lambda表达式中的捕获形参名称不能和程序中的局部变量名称相同。

二、JDK8中的方法引用

通过方法的名称来指出引用的方法

java中的方法引用是通过:: ,在方法作用域中引用。

@FunctionalInterface注解的作用是
标记的接口只能有一个抽象方法、
JDK8接口中的静态方法和默认方法,都不算是抽象方法、接口默认继承java.lang.Object。所以显示覆盖的父类的方法也不算抽象方法

public class Car {
    @FunctionalInterface
    public interface Supplier<T> {
        T get();
    }
    //Supplier是jdk1.8的接口,这里和lamda一起使用了
    public static Car create(final Supplier<Car> supplier) {
        return supplier.get();
    }
    public static void collide(final Car car) {
        System.out.println("Collided " + car.toString());
    }
    public void follow(final Car another) {
        System.out.println("Following the " + another.toString());
    }
    public void repair() {
        System.out.println("Repaired " + this.toString());
    }
    public static void main(String[] args) {
        //构造器引用:它的语法是Class::new,或者更一般的Class< T >::new实例如下:
        Car car  = Car.create(Car::new);
        Car car1 = Car.create(Car::new);
        Car car2 = Car.create(Car::new);
        Car car3 = new Car();
        List<Car> cars = Arrays.asList(car,car1,car2,car3);
        //静态方法引用
        cars.forEach(Car::collide);
        System.out.println("===================静态方法引用========================");
        cars.forEach(Car::repair);
        System.out.println("==============特定类的任意对象的方法引用================");
        List<String> list = new ArrayList<>(  );
        list.add( "first" );
        list.add( "second" );
        list.add( "third" );
        list.add( "forth" );
        list.forEach( System.out::println );
    }
}

三、默认方法

jdk8中接口可以添加默认方法、只需要在方法前面添加一个default。

接口的好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类。默认方法是为了解决接口的修改与现有的实现不兼容的问题。

当一个类继承了多个接口且默认方法冲突的解决方法

public interface Vehicle {
    default void print(){
        System.out.println("我是一辆车");
    }
    static void blow(){
        System.out.println("按喇叭");
    }
}
public interface FourWheeler {
    default void print(){
        System.out.println("我是一辆四轮车");
    }
}
public class Car implements Vehicle,FourWheeler {

//    //指定调用的方法
//    @Override
//    public void print() {
//        vehicle.super.print();
//    }
    
//    //两个继承的接口又重复方法
//    //重写继承的方法
//    @Override
//    public void print() {
//        System.out.println("我是一辆车");
//    }

 public void print(){
        Vehicle.super.print();
        FourWheeler.super.print();
        Vehicle.blow();
        System.out.println("我是一辆车");
    }

    public static void main(String[] args) {
        Vehicle vehicle = new Car();
        vehicle.print();
    }
}

两种方法分别是继承类自己定义重写继承得方法、显示指定继承接口的默认方法;

四、函数接口式实例

函数式接口的特点:

函数式接口(FunctionalInterface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。

函数式接口可以被隐式转换为lambda表达式。

函数式接口可以现有的函数友好地支持 lambda。

JDK8之后又引入了许多函数接口。

 

BiConsumer<T,U>代表了一个接受两个输入参数的操作,并且不返回任何结果

BiFunction<T,U,R>

代表了一个接受两个输入参数的方法,并且返回一个结果
BiPredicate<T,U>代表了一个两个参数的boolean值方法
Predicate <T> 它接受一个输入参数 T,返回一个布尔值结果。
ToIntFunction<T>接受一个输入参数,返回一个int类型结果。

 

 

 

 

 

 

函数式接口的实例

利用Predicate <T> 、将lambda表达式中的判断是否为空来遍历所有元素

public class InterfaceJDK8Test {

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9 );

//        Predicate<Integer> predicate = n->true;
//        n 是一个参数传递到 Predicate 接口的 test 方法
//        n 如果存在则 test 方法返回 true
        System.out.println("输出所有的数据");
        eval( list,n->true ); //n->true 创建了一个匿名的lambda

//        输出所有的偶数
//        传入n到Predicate中、n能整出2的是偶数
        System.out.println("输出所有的偶数");
        eval( list,n->n%2==0 );
    }

    public static void eval(List<Integer> list, Predicate<Integer> predicate) {
        for(Integer n: list) {
            if(predicate.test(n)) {
                System.out.println(n + " ");
            }
        }
    }
}

五、JDK8 steam 流

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

Stream使用一种类似用SQL语句从数据库查询数据的直观方式来提供一种对Java集合运算和表达的高阶抽象。

Stream(流)是一个来自数据源的元素队列并支持聚合操作

元素:是特定类型的对象,形成一个队列。Java中的Stream并不会存储元素,而是按需计算。

数据源 :流的来源。可以是集合,数组,I/O channel,产生器generator等。

聚合操作: 类似SQL语句一样的操作,比如filter, map, reduce, find,match, sorted等。

java中流的使用

生成串行流(stream())和并行流(parallelStream() )

public static void main(String[] args) {
        //创建串行流
        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
        long begins = System.currentTimeMillis();
        List<String> filtered = strings.stream().filter( string ->   !string.isEmpty()).collect( Collectors.toList());
        long ends = System.currentTimeMillis();
        System.out.println("串行消耗时间"+(ends-begins)+"ms");
        //创建并行流
        List<String> stringp = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
        long beginp = System.currentTimeMillis();
        int countp = (int) stringp.parallelStream().filter(string -> string.isEmpty()).count();
        long endp = System.currentTimeMillis();
        System.out.println("并行消耗时间"+(endp-beginp)+"ms");
}
//打印
串行消耗时间82ms
并行消耗时间5ms

forEach()

       // forEach     生成10个随机数, 并且打印 limit(n) 用于获取流的个数
        Random random = new Random();
        random.ints().limit(10).forEach(System.out::println);

map()    map 方法用于映射每个元素到对应的结果

//      map方法,使用map方法一一对应结果映射
        List<Integer> list = Arrays.asList( 3, 2, 2, 3, 7, 3, 5 );
        List<Integer> squaresList = list.stream().map(i -> i * i).distinct().collect(Collectors.toList());
        eval(squaresList,n->true);

filter()  用于通过设置条件过滤出元素

//      filter方法  设置条件过滤出元素
        List<String> stringss = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
        int count = (int) stringss.stream().filter(string -> !string.isEmpty()).count();
        System.out.println("filter后的数量:"+count);

sorted () 于对流进行排序。默认排序是字典排序

//      sorted 获取10个随机数、并把他们排序打印
        Random randoms = new Random();
        System.out.println("打印出排序的随机数");
        randoms.ints().limit(10).sorted().forEach(System.out::println);

Collectors() 实现了很多归约操作,例如将流转换成集合和聚合元素,实现了很多归约操作,例如将流转换成集合和聚合元素

   统计
        List<Integer> numbers = Arrays.asList(3, -2, 2, 3, 7, 3, 5);
        IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
        System.out.println("列表中最大的数 : " + stats.getMax());
        System.out.println("列表中最小的数 : " + stats.getMin());
        System.out.println("所有数之和 : " + stats.getSum());
        System.out.println("平均数 : " + stats.getAverage());

六、JDK8 Optional类

Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。

Optional 类的引入很好的解决空指针异常。

Optional提供的方法

static <T> Optional<T> empty()返回空的 Optional 实例。
boolean equals(Object obj)判断其他对象是否等于 Optional
Optional<T> filter(Predicate<? super <T> predicate)如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Option Optional。
T get()如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException
void ifPresent(Consumer<? super T> consumer)如果值存在则使用该值调用 consumer , 否则不做任何事情
static <T> Optional<T> ofNullable(T value)如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional
public class Java8Tester {
    public static void main(String args[]) {
        Java8Tester java8Tester = new Java8Tester();
        Integer value1 = null;
        Integer value2 = new Integer(10);
        // Optional.ofNullable - 允许传递为 null 参数
        Optional<Integer> a = Optional.ofNullable(value1);
        // Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
        Optional<Integer> b = Optional.of(value2);
        System.out.println(java8Tester.sum(a, b));
    }

    public Integer sum(Optional<Integer> a, Optional<Integer> b) {
        // Optional.isPresent - 判断值是否存在
        System.out.println("第一个参数值存在: " + a.isPresent());
        System.out.println("第二个参数值存在: " + b.isPresent());
        // Optional.orElse - 如果值存在,返回它,否则返回默认值
        Integer value1 = a.orElse(new Integer(0));
        //Optional.get - 获取值,值需要存在
        Integer value2 = b.get();
        return value1 + value2;
    }
}

参考博客:https://blog.youkuaiyun.com/yitian_66/article/details/81010434

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值