JDK1.8新特性及常用新特性

JDK1.8的新特性

  • *Lambda表达式

  • 新的日期API——Date time

  • 引入Optional——防止空指针异常

  • *接口的默认方法和静态方法

  • *新增方法引用格式

  • *新增Stream类

  • 注解相关的改变

  • 支持并行(Parallel)数组

  • 对并发类(Concurrency)的扩展

  • JavaFx

1.接口的默认方法和静态方法

  • 在设计接口方法时使用default关键字,方法可以拥有方法体,所有子类默认实现(不用自己写,可以覆盖)
  • 接口的静态方法不会被实现类继承

例:

@FunctionalInterface
public interface MyFunctionalInterface {
    /**
     * 有且仅有一个抽象方法
     */
    void method();
    /**
     * 静态方法
     */
    static void get(){
    }
    /**
     * 实现接口方法体
     */
    default void defaultMethod() {
        System.out.println("接口默认方法!");
    }
}
@FunctionalInterface:在编译期起作用,编译期强制检查该接口是否符合函数式接口的条件,不符合就报错;即使不适用该注解,只要满足函数式接口的定义即函数式接口。

2.函数式接口

函数式思想:只关注做什么,不关注怎么做。

  • 有且仅有一个抽象方法的接口
  • 可以适用于Lambda使用的接口(只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导)

格式:

public interface 接口名称{
    返回值 方法名称();
}

3.Lambda表达式(使用前提必须式函数式接口)

1.语法

三要素:参数、箭头、代码 即 (参数1,参数2…)->{}

  1. 无参时使用括号(),有参数使用逗号分隔
  2. 箭头是固定写法
  3. 大括号相当于方法体

2.Lambda省略规则

  1. 参数类型可以省略,但是只能同时省略所有参数类型,否则都不要省略
  2. 如果参数有且仅有一个,小括号可以省略
  3. 如果大括号内的语句有且仅有一条,那么无论是否又返回值,return、大括号、分号都可以省略

3.Lambda的延迟执行

解决的问题:有些场景下的代码执行后结果不一定会被使用,造成性能浪费

  1. 浪费案例
private void log(int level,String msg) {
    if(level == 1){
        System.out.println(msg);
    }
}

@Test
public void testStringConcat() {
    String str1 = "hhh";
    String str2 = "csl";
    String str3 = "csl123";
    log(1,str1+str2+str3);
}

​ 存在问题:无论level是否满足条件,log的第二个参数的那三个字符串一定会首先进行拼接并传入方法,然后才开始判断level。

  1. 使用Lambda优化案例:
private void log2(int level, MessageBuilder builder){
    if (level == 1) {
        System.out.println(builder.builderMessage());
    }
}

/**
 *  使用Lambda表达式实现字符串的拼接,并验证了延时执行
 */
@Test
public void testStringConcatLambda() {
    String str1 = "hhh";
    String str2 = "csl";
    String str3 = "csl123";
//      Lambda方式进行延时执行
//      如果不符合要求,lambda将不会执行;即level=2时不会执行
    log2(1, () -> str1+str2+str3);
}

4.使用Lambda作为参数和返回值

​ 如果方法的参数是一个函数式接口类型,那么就可以使用Lambda表达式进行替代。使用Lambda表达式作为方法参数,就是使用函数式接口作为方法参数。 例如 java.lang.Runnable接口就是一个函数式接口,假设有一个 startThread方法使用该接口作为参数,那么就可以使用Lambda进行传参。这种情况其实和Thread类的构造方法参数为Runnable没有本质区别。

4.常用函数式接口

  • 函数型接口
  • 供给型接口
  • 消费型接口
  • 判断型接口

1.函数型

有参数,且需要返回值。

@FunctionalInterface
public interface Function<T, R> {
    /**
    *根据类型T的参数获取类型R的结果
    */
    R apply(T t);
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }
    /**
    *先进行操作再进行操作
    */
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

public class FunctionTest {
    @Test
    public void testFunction(){
        int num = parseInteger(
                Integer::parseInt,
                "10"
        );
        System.out.println(num);
    }
    private Integer parseInteger(Function<String,Integer> function,String str){
        return function.apply(str);
    }

    /**
     * 自定义函数模型拼接
     */
    @Test
    public void testAge(){
        String str = "csl,16";
        int ageNum = getAgeNum(
                s -> s.split(",")[1],
                Integer::parseInt,
                i -> i + 100, str
        );
        System.out.println(ageNum);
    }
    /**
     *
     * @param one 将字符串截取数字年龄部分,得到字符串
     * @param two 将上一步的字符串转换为int类型的数字
     * @param three 将上一步的int数字累加100得到的结果
     * @param str 处理的字符串
     * @return 返回处理结果
     */
    private int getAgeNum(Function<String,String> one,Function<String,Integer> two,Function<Integer,Integer> three,String str) {
        return one.andThen(two).andThen(three).apply(str);
    }
}

2.供给型

无参数,指定返回值类型,经常用于只关注过程的代码。

@FunctionalInterface
public interface Supplier<T> {
    /**
     * 用来获取一个泛型参数指定类型的对象数据,即对外提供
     */
    T get();
}

public class SupplierTest {
    @Test
    public void testSupplier() {
        User user = getUser(User::new);
        System.out.println(user);
    }
    private User getUser(Supplier<User> supplier){
        return supplier.get();
    }
	
    /**
    * 获取最小值
    */
    @Test
    public void testMin() {
        int[] arr = {12,54,65,43,76,98,9};
        int minNum = getMin(() -> {
            int min = arr[0];
            for (int item : arr
            ) {
                if (item < min) {
                    min = item;
                }
            }
            return min;
        });
        System.out.println(minNum);
    }
    private int getMin(Supplier<Integer> supplier){
        return supplier.get();
    }
}

3.消费型

不需要返回值,有参数,经常用于迭代。

@FunctionalInterface
public interface Consumer<T> {
    
    /**
    *消费一个指定泛型的数据
    */
    void accept(T t);
    /**
    *参数和返回值都是Consumer类型;首先做一个操作再做一个操作
    */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

public class ConsumerTest {
    /**
     * 单个参数
     */
    @Test
    public void testConSummerTest(){
        User user = new User();
        setUserDefaultSex(u -> u.setSex("男"),user);
        System.out.println(user);
    }
    private void setUserDefaultSex(Consumer<User> conSummer,User user) {
        conSummer.accept(user);
    }

    /**
     * 一个参数
     */
    @Test
    public void testConSummerTest2(){
        User user = new User();
        setUserDefaultNameAndSex(u -> u.setSex("男"),u->u.setName("张三"),user);
        System.out.println(user);
    }
    private void setUserDefaultNameAndSex(Consumer<User> one,Consumer<User> two,User user) {
        one.andThen(two).accept(user);
    }

    /**
     * 多个参数
     */
    @Test
    public void testConSummerTest3(){
        User user = new User();
        setUserDefault(u -> u.setSex("男"),u->u.setName("张三"),u->u.setId(1),user);
        System.out.println(user);
    }
    private void setUserDefault(Consumer<User> one,Consumer<User> two,Consumer<User> three,User user) {
        one.andThen(two).andThen(three).accept(user);
    }
}

4.判断型

返回true/false,经常用于判断。

@FunctionalInterface
public interface Predicate<T> {
    /**
    *用于条件判断的场景
    */
    boolean test(T t);
    /**
    *与
    */
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
    /**
    *取反
    */
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }
    /**
    *或
    */
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

public class PredicateTest {
    /**
     * 一个条件
     */
    @Test
    public void testPredicate() {
        strLongThan(
                s->s.length()>5,"实例"
        );
    }
    private void strLongThan(Predicate<String> predicate,String str) {
        boolean flag = predicate.test(str);
        System.out.println("判断结果:"+flag);
    }
    /**
     * 两个条件
     */
    @Test
    public void testSuccess(){
        successThan(
                s->s.contains("高"),s->s.contains("帅"),"高富"
        );
    }
    private void successThan(Predicate<String> one,Predicate<String> two,String str) {
        boolean flag = one.and(two).test(str);
        System.out.println("强吗:"+flag);
    }
    /**
     * 集合筛选
     */
    @Test
    public void testFilter() {
        String[] array = {"迪丽热巴,女","马儿扎哈,男","地瓜嘎嘎,男","略略略,女"};
        List<String> list = filter(
                s -> s.split(",")[0].length() == 4,
                s -> "男".equals(s.split(",")[1]), array
        );
        System.out.println(list);
    }
    private List<String> filter(Predicate<String> one,Predicate<String> two,String[] arr){
        List<String> list = new ArrayList<>(8);
        for (String s: arr
             ) {
            boolean flag = one.and(two).test(s);
            if (flag){
                list.add(s);
            }
        }
        return list;
    }
}

5.方法引用

方法引用符:::(双冒号)

  1. 通过对象名引用成员方法;
  2. 通过类名称引用静态方法;
  3. 通过super引用成员方法;
  4. 通过this引用成员方法。

6.Stream流

​ 专注于做什么,而不是怎么做;解决集合中的常见问题。

1.获取流

List<String> list = new ArrayList<>(8);
Set<String> set = new HashSet<>(8);
Map<String,Object> map= new HashMap<String, Object>(8);
String[] array = {"陈西瓜","张收到","呜哈哈","陈开心","王开心","张开心","样开心","李难过"};
  • Collection接口实现类获取流

    //  Collection接口的实现类获取流
    Stream<String> streamList = list.stream();
    Stream<String> streamSet = set.stream();
    }
    
  • Map接口实现类获取流

    //  Map接口的实现类获取流
    Stream<String> streamKey = map.keySet().stream();
    Stream<Object> streamValue = map.values().stream();
    
  • 数组获取流

    //  数组获取流
    Stream<String> streamArray = Stream.of(array);
    

2.流的常用方法

List<String> list = new ArrayList<>(8);
list.add("陈西瓜");
list.add("张收到");
list.add("呜哈哈");
list.add("陈开心");
list.add("王开心");
list.add("张开心");
list.add("杨开心");
list.add("李难过");
  • 逐一处理:forEach
list.stream().forEach(System.out::print);
  • 过滤:filter
list.stream().filter(e->e.contains("开心"));
  • 映射:map(将stream里面的内容映射到另一个stream中)
list.stream().map(e -> e.substring(2));
  • 统计个数:count
list.stream().count();
  • 取用前n个:limit
list.stream().limit(n);
  • 跳到前n个:skip
list.stream().skip(n);
  • 通过skip+limit实现分页效果:skip+limit
list.stream().skip(n).limit(n);
  • 合并两个流:concat
Stream.concat(one, two);
  • 将流转换为集合:collect
list.stream().collect(Collectors.toList());

关于流的常用方法使用案例:

@Test
public void testCommonMethod() {
    List<String> list = new ArrayList<>(8);
    list.add("陈西瓜");
    list.add("张收到");
    list.add("呜哈哈");
    list.add("陈开心");
    list.add("王开心");
    list.add("张开心");
    list.add("杨开心");
    list.add("李难过");
    System.out.print("逐一处理:");
    list.stream().forEach(System.out::print);
    System.out.print("\n过滤:");
    list.stream().filter(e->e.contains("开心")).forEach(System.out::print);
    System.out.print("\n映射(将stream里面的内容映射到另一个stream中):");
    list.stream().map(e -> e.substring(2)).forEach(System.out::print);
    System.out.print("\n统计个数. 即list.size():  ");
    System.out.print(list.stream().count());
    System.out.print("\n取用前3个:   ");
    list.stream().limit(3).forEach(System.out::print);
    System.out.print("\n跳到前1个:");
    list.stream().skip(1).forEach(System.out::print);
    System.out.print("\n通过limit+skip可以实现分页效果:");
    list.stream().skip(2).limit(2).forEach(System.out::print);
    System.out.print("\n合并两个流:");
    Stream<String> one = list.stream().skip(0).limit(2);
    Stream<String> two = list.stream().skip(5).limit(2);
    Stream.concat(one, two).forEach(System.out::print);
    System.out.print("\n将流转为集合:");
    List<String> collect = list.stream().collect(Collectors.toList());
    collect.forEach(System.out::print);
}

你可能感兴趣的:(Java)