22 新特性介绍

302 阅读5分钟

1 Java 8 的新特性

Java 8 中新增加的新特性有函数式接口、Lambda表达式、方法引用、Stream接口、Optional类等重要新特性,下面会详细介绍这些新特性。

1.1 函数式接口

函数式接口主要指只包含一个抽象方法的接口,比如Runnable、Comparator接口等,在 Java 8中提供了@Functionallnterface注解来定义函数式接口,若定义的接口不符合函数式接口的规范便会报错。

为了更好的使用函数式接口,Java 8中新增了function包,该包包含了常用的函数式接口,常用方法如下:

接口名称方法声明功能介绍
Consumervoid accept(T t)根据参数执行操作
SupplierT get()得到一个返回值
Function<T,R>R apply(T t)根据指定的参数执行操作并返回
Predicateboolean test(T t)判断指定的参数是否满足条件

函数式接口使用实例:

package task22;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

public class FunctionInterface {
    public static void main(String[] args) {
        Person person=new Person();
        System.out.println(person);
        Consumer<String> consumer=new Consumer<String>() {
            @Override
            public void accept(String s) {
                person.setName(s);
            }
        };
        consumer.accept("zhangfei");
        System.out.println(person);
        Supplier<String> supplier=new Supplier<String>() {
            @Override
            public String get() {
                return person.getName();
            }
        };
        System.out.println("获取到的姓名是"+supplier.get());
        Function<String,Integer> function=new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return Integer.parseInt(s);
            }
        };
        System.out.println(function.apply("12345"));
        Predicate<Integer> p=new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                return person.getAge()>integer;
            }
        };
        person.setAge(23);
        System.out.println(p.test(18));

    }
}

1.2 Lambda表达式

Lambda表达式可以使代码变得更加简洁,同时也是实现函数式接口的重要方式,Lambda表达式的语法格式是:(参数列表)->{方法体;},其中()、{}以及return关键字都可以省略,方法体可以是表达式也可以是语句块。

使用Lambda表达式实现函数式接口的实例:

package task22;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

public class FunctionInterface {
    public static void main(String[] args) {
        Person person=new Person();
        System.out.println(person);
        Consumer<String> consumer=s->person.setName(s);
        consumer.accept("zhangfei");
        System.out.println(person);
        Supplier<String> supplier=()->person.getName();
        System.out.println("获取到的姓名是"+supplier.get());
        Function<String,Integer> function=(s)->Integer.parseInt(s);
        System.out.println(function.apply("12345"));
        Predicate<Integer> p=(i)->person.getAge()>i;
        person.setAge(23);
        System.out.println(p.test(18));

    }
}

1.3 方法引用

方法引用是指通过方法的名字来指向一个方法而不需要为方法引用提供方法体,该方法的调用交给函数式接口执行。

方法引用的语法格式是:使用一对冒号 ::将类或对象与方法名进行连接,通常使用方式如下:

  • 对象的非静态方法引用 ObjectName :: MethodName
  • 类的静态方法引用 ClassName :: StaticMethodName
  • 类的非静态方法引用 ClassName :: MethodName (适用于非静态方法中其中一个参数作为调用对象来调用方法的场合)
  • 构造器的引用 ClassName :: new
  • 数组的引用 TypeName[] :: new

方法引用是在特定场景下对Lambda表达式的一种简化表示,可与进一步简化代码的编写,减少代码的冗余。

方法引用的实例:

package task22;

import java.util.Arrays;
import java.util.Comparator;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

public class FunctionInterface {
    public static void main(String[] args) {
        Person person=new Person();
        System.out.println(person);
        Consumer<String> consumer=person::setName;
        consumer.accept("zhangfei");
        System.out.println(person);
        Supplier<String> supplier=person::getName;
        System.out.println("获取到的姓名是"+supplier.get());
        Function<String,Integer> function=Integer::parseInt;
        System.out.println(function.apply("12345"));
        Comparator<Integer> comparator=Integer::compareTo;
        System.out.println(comparator.compare(11, 22));
        Supplier<Person> supplier1=Person::new;
        System.out.println(supplier1.get());
        BiFunction<String,Integer,Person> biFunction=Person::new;
        System.out.println(biFunction.apply("guanyu", 33));
        Function<Integer,Person[]> function1=Person[]::new;
        System.out.println(Arrays.toString(function1.apply(3)));

    }
}

1.4 Stream接口

Stream接口是对集合功能的增强,可以对集合进行复杂的查找、过滤、筛选等操作。

使用步骤:

  • 创建Stream,通过一个数据源来获取流
  • 转换Stream,每次转换返回一个新的Stream对象
  • 对Stream进行聚合操作并产生结果

Stream创建方式:

  • 调用集合的默认方法来获取流,如 default Stream stream()
  • 通过数组工具类的静态方法获取流,如 static IntStream stream(int[] arr)
  • 通过Stream接口的静态方法获取流,如 static Stream of(T... values)
  • 通过Stream接口的静态方法获取流,如 static Stream generate(Supplier< ? extends T> s)

常用方法如下:

方法声明功能介绍
Stream filter(Predicate<? super T> pre)返回一个包涵匹配元素的流
Stream distinct()返回不包含重复元素的流
Stream map(Function<? super T, ? extends R)返回每个处理过元素组成的流
Stream sorted()返回经过自然排序后元素组成的流
void forEach(Consumer< ? super T> action)对流中每个元素执行操作

使用实例:

package task22;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

public class ListPerson {
    public static void main(String[] args) {
        List<Person> list=new ArrayList<>();
        list.add(new Person("zhangfei",32));
        list.add(new Person("guanyu",35));
        list.add(new Person("xiaoqiao",22));
        list.add(new Person("daqiao",20));
        list.add(new Person("liubei",39));
        for(Person p:list){
            System.out.println(p);
        }
        list.stream().filter(person -> person.getAge()>25).forEach(System.out::println);
        list.stream().map(new Function<Person, Integer>() {
            @Override
            public Integer apply(Person person) {
                return person.getAge();
            }
        }).forEach(System.out::println);
        System.out.println("-----------------------------");
        list.stream().map(person -> person.getAge()).forEach(System.out::println);
        System.out.println("-----------------------------");
        list.stream().map(Person::getAge).forEach(System.out::println);
    }
}

1.5 Optional类

Optional类可以理解为一个容器,其值可以为null或者不是null,代表一个值存在或不存在。Optional类可以很好的解决空指针异常的问题,不用显式进行空值检测,其常用方法如下:

方法声明功能介绍
static Optional ofNullable(T value)根据参数值来得到Optional对象
Optional map(Function< ? super T, ? extends U> mapper )根据参数规则的结果来得到Optional对象
T orElse(T other)当值存在就返回,否则就返回other的数值

具体实例:

package task22;

import java.util.Optional;

public class OptionalTest {
    public static void main(String[] args) {
        String str=null;
        Optional<String> optional=Optional.ofNullable(str);
        Optional<Integer> integer = optional.map(String::length);
        System.out.println("integer = "+integer);
        System.out.println(integer.orElse(0));
        System.out.println(optional.orElse("我是空的"));


    }
}

2 Java 9 的新特性

Java 9 的新特性这里主要提到的是模块化的使用以及钻石操作符的使用升级、集合工厂方法、InptuStream的增强等,下面会介绍这四个新特性: 模块化的使用

语法格式:在module-info.java文件中,可以使用新的关键字moulde来声明一个模块,具体如下 moudle 模块名称{

}

之所以提出模块化,是为了减少内存的开销,以及提供了可维护性和安全性,简化各种类库和大型应用的开发和维护

钻石操作符

在 Java 9 中允许在匿名内部类中使用钻石操作符(可以看做棱形语法在匿名内部类中推广),具体实例见下面代码:

Consumer<String> consumer1=new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };



//钻石操作符的使用
Consumer<String> consumer1=new Consumer<>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };

集合工厂方法

在集合中增加了静态工厂方法of,实现了不可变实例的创建,该集合工厂的特点是:不可改变体现在无法对集合进行添加、删除、修改等操作,并且还不允许添加null元素对象。

引入集合工厂的意义:

  • 保证线程安全:在并发程序中既保证了线程安全,又增强了并发效率
  • 被不可信的类库使用时很安全
  • 对象不支持修改操作,会节省空间和时间的开销
  • 可以当做常量看待,并且对象永远不会被改变

InputStream增强

InputStream类中新增了transferTo方法实现将数据直接传输到OutputStream中,具体使用见下面:

package task22;

import java.io.*;

public class InputStreamTest {
    public static void main(String[] args)  {
        InputStream inputStream=null;
        OutputStream outputStream=null;
        
        try {
            inputStream=new FileInputStream("a.txt");
            outputStream=new FileOutputStream("b.txt");
            inputStream.transferTo(outputStream);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(null!=outputStream){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if(null!=inputStream){
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }


    }
}

3 Java 10 的新特性

Java 10 的新特性需要关注的是局部变量的类型推断,可与使用var作为局部变量类型推断标识符,此符号仅适用于局部变量,增强for循环的索引,以及传统for循环的本地变量。

需要注意的是var不能用在方法的形式参数,构造函数的形式参数,方法返回类型,字段,catch形式参数或任何其他类型的变量声明。

引入var标识符的好处:

  • 避免信息冗余
  • var不是关键字,只是一个保留的类型名称,可以用作变量,方法名或包名,但是不能作为类或接口的名字
  • 可读性好

4 Java 11 的新特性

Java 11 新特性值得关注的是简化编译运行操作,可以直接使用java命令一次性进行编译和运行操作,但是需要注意两点是:

  • 执行源文件中的第一个类必须包含主方法(main方法)
  • 不可以使用其他源文件中自定义的类

除此之外还给String类增加了以下几个新方法:

方法声明功能介绍
boolean isBlank()判断字符串是否为空或制暴汗空白代码点
Optional map(Function<? super T, ? extends U> mapper)根据参数规则的结果得到Optional类的对象
T orElse(T other)当值存在时返回值,否则返回参数指定的值