JDK1.8新特性lambda表达式&函数式接口(一)

java1.8 lambda(一)

  • 1.函数式接口
    • 1.1default 关键字
    • 1.2default 实例
  • 2.lambda表达式&函数式接口
    • 2.1什么是lambda表达式
    • 2.2 lambda表达式语法
    • 2.3 lambda表达式使用案例
    • 2.4 lambda表达式注意事项
  • 常见的函数式接口
    • 1 Consumer
    • 2 Function
    • 3 Predicate
  • 流式编程 StreamAPI

1.函数式接口

lambda表达式需要函数式接口的支持 ==
所谓的函数式接口,是指只有一个抽象方法(这里注意不是只有一个方法,1.8以及后 interface中可以有默认实现的方法关键字是default,如果他有两个及以上抽象方法,就不是函数式接口)的接口
== jdk8帮我们提供了一个注解,帮助我们检查编译时是否合格

@FunctionInterface

1.1default 关键字

default关键字在API中的解释为
意思是默认方法能够向库的接口添加新功能,并确保与为这些接口的旧版本编写的代码兼容。并且不用在其子类进行逐个实现。

default是在java8中引入的关键字,也可称为Virtual
extension methods——虚拟扩展方法。是指,在接口内部包含了一些默认的方法实现(也就是接口中可以包含实现的方法体,这打破了Java之前版本对接口的语法限制),从而使得接口在进行扩展的时候,不会破坏与接口相关的实现类代码。

1.2default 实例

1、调用父接口实现

package main.java.defaultt;

@FunctionalInterface
public interface Interface1 {
    default void sayhello(String hello){
        System.out.println(hello);
    }

    abstract void test1();

//    abstract void test2();
}

package main.java.defaultt;

public class Test implements Interface1{

    @Override
    public void test1() {

    }

    public static void main(String[] args) {
        Test test = new Test();

        test.sayhello("ya");
    }
}

输出为 ya 没有问题

2、同时继承两个接口 – 如果抽象方法同名则必须重新实现
否则报错
JDK1.8新特性lambda表达式&函数式接口(一)_第1张图片
发生这种情况的原因是,实现类Test即实现了接口Interface1又实现了接口Interface2,恰巧两个接口中都定义可相同的默认方法。说白了就是编译器此时已经被干懵了,当我们在Test类中调用方法时,它不知道该去调用Interface1的默认方法还是去调用Interface2的方法。解决方法就是在实现类中实现该方法

我们都知道接口是可以有多实现的,如果在两个接口中都有了default修饰的相同方法,那么在实现类中程序将不知道该使用哪个default的方法了,这时就要显示声明使用哪一个

package main.java.defaultt;

package main.java.defaultt;

public interface Interface2 {
    default void sayhello(String hello){
        System.out.println("2:"+hello);
    }

    abstract void test1();
}

这样的实现是本类自己实现 类优先

package main.java.defaultt;

public class Test implements Interface1,Interface2{

    /**这里有两种实现
     * 1.本类重新实现
     * @param hello
     */
    @Override
    public void sayhello(String hello) {
        System.out.println("我自己的"+hello);
    }

    @Override
    public void test1() {

    }

    public static void main(String[] args) {
        Test test = new Test();

        test.sayhello("ya");
    }
}

结果
JDK1.8新特性lambda表达式&函数式接口(一)_第2张图片

这样的方式是指定父类的实现方法 充分证明了类优先于接口

package main.java.defaultt;

public class Test implements Interface1,Interface2{

    /**这里有两种实现
     * 2.指定父类的实现方法
     * @param hello
     */
    @Override
    public void sayhello(String hello) {
        Interface1.super.sayhello(hello);
        Interface2.super.sayhello(hello);
    }

    @Override
    public void test1() {

    }

    public static void main(String[] args) {
        Test test = new Test();

        test.sayhello("ya");
    }
}

结果
JDK1.8新特性lambda表达式&函数式接口(一)_第3张图片

2.lambda表达式&函数式接口

2.1什么是lambda表达式

lambda表达式可以理解为一种匿名函数的的代替
lambda允许将函数作为一个方法的参数(函数作为方法的参数传递),将代码像数据一样传递,目的是简化代码的编写

Lambda 表达式是 JDK8 的一个新特性,可以取代大部分的匿名内部类,写出更优雅的 Java 代码,尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构。
JDK 也提供了大量的内置函数式接口供我们使用,使得 Lambda 表达式的运用更加方便、高。
在这里重点关注的是函数式编程:即java中是将带有单个抽象方法的接口(或者,几乎都不是抽象类)作为函数类型。
创建函数对象的主要方式是通过匿名类。

2.2 lambda表达式语法

函数式接口   变量名 = (参数1,参数2.....)->{
	//方法体
}	

2.3 lambda表达式使用案例

  • 案例1:
package main.java.lambda;

public class Test {
    public static void main(String[] args) {
        //匿名内部类 -- 这种方式会生成匿名内部类文件
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("hello,this is old way");
            }
        };

        new Thread(runnable).start();

        //lambda表达式
        Runnable runnable1 = ()->{System.out.println("hello,this is lambda way");};
        new Thread(runnable1).start();

        //lambda表达式简化 方法体只有一条语句时可以不写大括号 {}
        Runnable runnable2 = ()->System.out.println("hello,这是简化后的lambda表达式");
        new Thread(runnable2).start();

        //其实可以最简化即在参数中去使用lambda或者创建匿名内部列
        new Thread(()->System.out.println("这是最简化的写法")).start();
    }
}


hello,this is old way
hello,this is lambda way
hello,这是简化后的lambda表达式
这是最简化的写法

Process finished with exit code 0
  • 案例2:
       //比较器 传统模式 匿名类或者实现接口
       Comparator<String> comparator = new Comparator<String>() {
           @Override
           public int compare(String o1, String o2) {
               return o1.length()-o2.length();
           }
       };
       TreeSet<String> treeSet = new TreeSet<>(comparator);

       //lambda 表达式
       Comparator<String> comparator1 = (o1,o2)->o1.length()-o2.length();
       TreeSet<String> treeSet1 = new TreeSet<>(comparator1);

       TreeSet<String> treeSet2 = new TreeSet<>((o1,o2)->o1.length()-o2.length());
   	   TreeSet<String> treeSet3 = new TreeSet<>((o1,o2)->{return o1.length()-o2.length();});

2.4 lambda表达式注意事项

lambda引入了新的操作符: -> ,->将表达式分成两部分
左侧:(参数1,参数2.....)表示参数列表
右侧: { } 内部是方法体
1. 形参列表的数据类型会自动推断 ;
2. 如果形参列表为空,只需保留();
3. 如果形参只有一个,()可以省略,只需要参数名称即可;
4. 如果执行语句只有一句,且无返回值,{}可以省略,若有返回值,若想省去{},则必须省去return,且执行语句也保证只有一句;
5. lambda 表达式不会生成一个单独的内部类文件;
6. lambda表达式若访问了局部变量,则局部变量必须是final的,若是局部变量没有加final关键字,系统会自动添加,此后在修改该局部变量,汇报错;

常见的函数式接口

1 Consumer

Consumer是一个函数式编程接口; 顾名思义,Consumer的意思就是消费,即针对某个东西我们来使用它,
因此它包含有一个有输入而无输出的accept接口方法;

   void accept(T t);

除accept方法,它还包含有andThen这个方法;
其定义如下:

   void accept(T t);
       default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }

测试

        Consumer c = System.out::println;
        Consumer c2 = n -> System.out.println(n + "-c2");

        //执行完c后再执行c2的Accept方法
        c.andThen(c2).accept("Consumer");

        //连续执行c的Accept方法
        c.andThen(c).andThen(c).andThen(c).accept("testFun");

Consumer
Consumer-c2
testFun
testFun
testFun
testFun

2 Function

Function也是一个函数式编程接口;它代表的含义是“函数”,而函数经常是有输入输出的,因此它含有一个apply方法,包含一个输入与一个输出;
除apply方法外,它还有compose与andThen及indentity三个方法,其使用见下述示例;

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

测试

        Function<String, String> f = s -> s+"f|";
        Function<String, String> g = s -> s+"g|";

        /**
         * 下面表示在执行f时,先执行g,并且执行f时使用g的输出当作输入。
         * 相当于以下代码:
         * String a = g.apply("1");
         * System.out.println(f.apply(a));
         */
        System.out.println(f.compose(g).apply("1"));

        /**
         * 表示执行f的Apply后使用其返回的值当作输入再执行g的Apply;
         * 相当于以下代码
         * String a = f.apply("2");
         * System.out.println(g.apply(a));
         */
        System.out.println(f.andThen(g).apply("2"));

        /**
         * identity方法会返回一个不进行任何处理的Function,即输出与输入值相等;
         */
        System.out.println(Function.identity().apply("a"));

1g|f|
2f|g|
a

3 Predicate

Predicate为函数式接口,predicate的中文意思是“断定”,即判断的意思,判断某个东西是否满足某种条件; 因此它包含test方法,根据输入值来做逻辑判断,其结果为True或者False。

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

它的使用方法示例如下:

        Predicate<String> p = o -> o.equals("test");
        Predicate<String> g2 = o -> o.startsWith("t");

        Assert.assertTrue(p.test("test"));
        /**
         * negate: 用于对原来的Predicate做取反处理;
         * 如当调用p.test("test")为True时,调用p.negate().test("test")就会是False;
         */
        Assert.assertFalse(p.negate().test("test"));

        /**
         * and: 针对同一输入值,多个Predicate均返回True时返回True,否则返回False;
         */
        Assert.assertTrue(p.and(g2).test("test"));

        /**
         * or: 针对同一输入值,多个Predicate只要有一个返回True则返回True,否则返回False
         */
        Assert.assertTrue(p.or(g2).test("ta"));

        //对当前操作进行"="操作,即取等操作,可以理解为 A == B
        Stream.of("String","TRE").filter(Predicate.isEqual("TRE")).forEach(System.out::println);

TRE

流式编程 StreamAPI

链接: 简单全面学习JDK1.8新特性之流式编程-SreamAPI(二).

你可能感兴趣的:(学习教程)