Java8特性

Java8特性

接口定义增强

JDK1.8之前,接口的组成只有全局变量抽象方法。从JDK1.8开始,接口的组成增加了。
假设:现有一个接口,其子类有2W个。现在发现该接口功能不足,要增加一个方法,该方法对于所有子类而言的功能是一样的(即方法体是一样的)。此时要修改每个子类的方法,要修改2W次。
上述问题在JDK1.8中不存在,因为其允许接口中定义普通方法,但普通方法必须使用default定义。

interface Fruit {
    public void print(); // 接口原本定义的方法

    default public void fun() { // 普通方法
        System.out.println("JDK1.8");
    }
}

class Apple implements Fruit {
    @Override
    public void print() {
        System.out.println("苹果");
    }
}

public class Demo {
    public static void main(String[] args) {
        Fruit f = new Apple();
        f.fun();
        f.print();
    }
}

除了使用default定义方法,还可以使用static定义方法
范例:定义static方法

interface Fruit {
    public void print(); // 接口原本定义的方法

    default public void fun() { // 普通方法
        System.out.println("JDK1.8");
    }

    static void get() {
        System.out.println("直接由接口调用");
    }
}

class Apple implements Fruit {
    @Override
    public void print() {
        System.out.println("苹果");
    }
}

public class Demo {
    public static void main(String[] args) {
        Fruit f = new Apple();
        f.fun();
        f.print();
        Fruit.get();
    }
}

JDK1.8有个新功能:内部类访问方法参数时可以不加上final关键字。
这些新特性,完全打破了Java已有的代码组成形式。

Lamda表达式

Lamda属于函数式编程的概念,下面通过匿名内部类,来分析函数式编程的产生目的。
范例:匿名内部类

interface Fruit {
    public void print(); // 接口原本定义的方法
}


public class Demo {
    public static void main(String[] args) {
        fun(new Fruit() {
            @Override
            public void print() {
                System.out.println("水果");
            }
        });
    }

    public static void fun(Fruit fru) {
        fru.print();
    }
}

上述代码中fun()最终需要的只是输出,但是由于Java的开发结构的完整性要求,不得不在这个核心语句上嵌套更多的内容。但是该做法过于严谨复杂,在JDK1.8引入函数式编程,简化过程。
范例:使用Lamda表达式

interface Fruit {
    public void print(); // 接口原本定义的方法
}

public class Demo {
    public static void main(String[] args) {
        fun(()-> System.out.println("水果"));
    }
    public static void fun(Fruit fru) {
        fru.print();
    }
}

Lamda语法有三种形式:

·(参数)->单行语句;
·(参数)->{单行语句};
·(参数)->表达式;

范例:观察有参单行

interface Fruit {
    public void print(String str); // 接口原本定义的方法
}

public class Demo {
    public static void main(String[] args) {
        // 首先要定义此表达式里面需要接收变量,单行语句直接进行输出
        fun((s) -> System.out.println(s));
    }

    public static void fun(Fruit fru) {
        fru.print("苹果"); // 设置参数的内容
    }
}

范例:编写多行语句

interface Fruit {
    public void print(String str); // 接口原本定义的方法
}

public class Demo {
    public static void main(String[] args) {
        // 首先要定义此表达式里面需要接收变量,单行语句直接进行输出
        fun((s) -> {
            s = s.toUpperCase();
            System.out.println(s);
        });
    }

    public static void fun(Fruit fru) {
        fru.print("Hello"); // 设置参数的内容
    }
}

范例:编写表达式

interface Fruit {
    public int add(int x, int y);
}

public class Demo {
    public static void main(String[] args) {
        // 首先要定义此表达式里面需要接收变量,单行语句直接进行输出
        fun((s1, s2) -> s1 + s2);
    }

    public static void fun(Fruit fru) {
        System.out.println(fru.add(10, 20));
    }
}

方法引用

对象引用的特点:不同对象可以操作同一块内容。而方法引用就是指为一个方法设置别名,相当于一个方法定义了不同的名字。
1、方法引用在Java8中一共定义了四种形式:

· 引用静态方法: 类名称::static 方法名称;
· 引用某个对象的方法:实例化对象::普通方法;
· 引用特定类型的方法:特定类::普通方法;
· 引用构造方法:类名称::new。

范例:引用静态方法
String类中的valueof():public static String valueof(int x)

package com.java.demo;

/**
 * 只有一个方法的接口
 * @param <P> 参数的数据类型
 * @param <R> 返回值的数据类型
 */
interface Math<P, R> {
    public R exchange(P p);
}

public class Demo {
    public static void main(String[] args) {
        // 覆写了exchange(),使其具有valueOf()的功能
        Math<Integer, String> math = String::valueOf;
        String msg = math.exchange(10000);
        // 将所有的0替换成9
        System.out.println(msg.replaceAll("0", "9"));
    }
}

范例:普通方法引用
String类中的toUpperCase():public String toUpperCase()

package com.java.demo;

interface Math<R> {
    public R upper();
}

public class Demo {
    public static void main(String[] args) {
        // 覆写了upper,使其具有toUpperCase的功能
        // toUpperCase是普通方法,必须由String对象调用
        // hello是String对象,代码如下
        Math<String> math = "hello"::toUpperCase;
        String msg = math.upper();
        System.out.println(msg);
    }
}

上述例子显示,要实现方法引用,必须要有接口,且该接口只能有一个方法。为了保证该接口只有一个方法,可对其进行注解说明。

@FunctionalInterface // 此为函数式接口,只能定义一个方法
interface ITest<R> {
    public R upper();
}

2、在进行方法引用的过程中,还有一种形式的引用(这种形式需要特定类的对象支持)。一般使用“类::方法”,引用的是类中的静态方法。但是这种形式也可以引用普通方法。
例如:在String类中有一个方法:public int compareTo(String anotherString),比较的形式是String对象1.compareTo(String对象2),即要引用该方法,需要有两个参数。
范例:引用特定类的方法

interface IMessage<P> {
    public int compare(P p1, P p2);
}

public class Demo {
    public static void main(String[] args) {
        IMessage<String> msg = String::compareTo;
        System.out.println(msg.compare("A", "B"));
    }
}

与之前相比,方法引用前不需要定义对象,可以理解为将对象定义在参数上。
范例:引用构造方法

interface IMessage<C> {
    public C create(String t, double p);
}

class Book {
    private String title;
    private double price;

    public Book(String title, double price) {
        this.title = title;
        this.price = price;
    }

    public String toString() {
        return "书名:" + this.title + ",价格:" + this.price;
    }
}

public class Demo {
    public static void main(String[] args) {
        IMessage<Book> msg = Book::new; // 引用构造方法
        // 虽然调用的是create(),实际引用了Book类的构造方法
        Book book = msg.create("Java开发", 66.6);
        System.out.println(book);
    }
}

对象引用是使用不同的名字,而方法引用需要一个函数接口。

内建函数式接口

1、JDK1.8中提供了一个包:java.util.function,提供有以下四个核心接口:

(1)功能性接口(Function):public interface Function<T,R>{public R apply(T t);}
|- 此接口需要接收一个参数,并且返回一个处理结果;
(2)消费型接口(Consumer):public interface Consumer{public void accept(T t);}
|- 此接口只负责接收数据(引用数据是不需要返回的),并且不返回结果;
(3)供给型接口(Suplier):public interface Supplier{public T get();}
|- 此接口不接收参数,但是可以返回结果
(4)断言型接口(Predicate):public interface Predicate{public boolean Test(T t);}
|- 进行判断操作使用;

在JDK1.8中存在以上四个功能型接口,所以很少会由用户去定义新的函数式接口。
范例:函数式接口——接收参数并返回处理结果
· String类有一个方法:public boolean startsWith(String str)

package com.java.demo;

import java.util.function.Function;

public class Demo {
    public static void main(String[] args) {
        Function<String, Boolean> fun = "##hello"::startsWith;
        System.out.println(fun.apply("##")); // true
    }
}

范例:消费型接口

package com.java.demo;

import java.util.function.Consumer;

class MyDemo {
    // 此方法没有返回值,但是有参数
    public void print(String str) {
        System.out.println(str);
    }
}

public class Demo {
    public static void main(String[] args) {
        Consumer<String> cons = new MyDemo()::print;
        cons.accept("Hello World");
    }
}

范例:供给型接口
· 引用String类的toUpperCase():public String toUpperCase();

package com.java.demo;

import java.util.function.Supplier;

public class Demo {
    public static void main(String[] args) {
        Supplier<String> sup = "hello"::toUpperCase;
        System.out.println(sup.get());
    }
}

范例:断言型接口
· String类中有equalsIgnoreCase()

import java.util.function.Predicate;

public class Demo {
    public static void main(String[] args) {
        Predicate<String> pre = "hello"::equalsIgnoreCase;
        System.out.println(pre.test("Hello"));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值