【第一天】JAVA8 函数式接口与Lambda表达式初步

在这里插入图片描述

概要

Java Lambda表达式是一种匿名函数,他是没有声明的方法,即没有访问修饰符,返回值声明和名字

作用

1. 传递行为,而不仅仅是值
2. 提升抽象层次
3. API重用性更好
4. 更加灵活

Lambda结构

  • 一个Lambda表达式可以有零个或多个参数
  • 参数的类型既可以明确声明,也可以根据上下文来推断。例如:(int a)与(a)效果相同
  • 所有参数需包含在圆括号内,参数之间用逗号相隔。例如:(a,b)或者(int a,int b)或(String a,String b,float c)
  • 空圆括号代表参数集为空。例如:()-> 42

Lambda 箭头左侧(参数)->箭头右侧(执行体) 当左侧没有参数时 左侧括号是不能省略的
在这里插入图片描述

public class Test1 {

    public static void main(String[] args) {

        List<Integer> list = Arrays.asList(1, 3, 8);

        /*
      1.  @FunctionalInterface 凡是一个类加上该注解 都是函数式接口
        请注意,加了改接口可以使用
        lambda表达式、方法引用或构造函数引用。

      2.满足以下规则 不然系统会给你生成一个错误信息
        1.类型是接口类型,而不是批注类型、枚举或类
        2.满足函数式接口要求
         */
        list.forEach(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.println(integer);
            }
        });

    }
}

关于函数式接口
1.如果一个接口只有一个抽象方法,那么改接口就是一个函数式接口
2.如果我们在某个接口声明@FunctionalInterface注解,那么编译就会暗中函数式接口定义来要求该接口
3.如果某个接口只有一个抽象方法,但我们并没有该接口声明@FunctionalInterface注解。那么编译器依旧会将该接口看做函数式接口。
4.注意,函数接口的实例可以用lambda表达式、方法引用或构造函数引用创建

Iterable

jdk1.5 ,实现该接口的类可以进行迭代 ,1.8以后集合都可以直接使用默认方法forEach方法进行迭代
(jdk8之后 接口可以写默认方法和 static实现方法)

在这里插入图片描述

forEach

doc文档
对Iterable的每个行为执行给定的操作,直到处理完所有行为或操作引发异常为止。除非实现类另有指定,否则按迭代顺序(如果指定了迭代顺序)执行操作。操作引发的异常将取决于调用方
forEach改方法是将==行为动作(函数 在java中一种特别的对象)==当做参数进行传递 在jdk1.8之前方法参数只能传递值
在这里插入图片描述
实例1

public class Test1 {

    public static void main(String[] args) {

        List<Integer> list = Arrays.asList(1, 3, 8);

        /*
      1.  @FunctionalInterface 凡是一个类加上该注解 都是函数式接口
        请注意,加了改接口可以使用
        lambda表达式、方法引用或构造函数引用。

      2.满足以下规则 不然系统会给你生成一个错误信息
        1.类型是接口类型,而不是批注类型、枚举或类
        2.满足函数式接口要求
         */
        list.forEach(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.println(integer);
            }
        });

        list.forEach(x-> System.out.println(x));

        Consumer<Integer> s = x-> System.out.println(x);
    }
}

Consumer(重要)

doc文档
代表着一个接受单个输入参数且不返回结果的操作。与大多数其他函数式接口不同,消费者希望通过副作用(就是可能会去修改接收单个参数)进行操作。类似Test1中accept执行给定行为具体操作给定的行为参数即可

当调用该接口可以直接使用Lambda表达式操作 如accept方法 ( T x)->方法体
在这里插入图片描述
在这里插入图片描述
实例2

@FunctionalInterface
interface MyIterfece {

    void test();

//    void test2(String s);

    /*
        为什么函数式接口里有两个抽象方法 系统不报错
        因为 该接口的实现类 一定继承于Object基类 基类存在toString()方法 无需实现类进行创建 所以函数式接口允许存在
        Object基类的抽象方法
     */
    @Override
    String toString();
}

class Test2 {

    public void meTest(MyIterfece myIterfece) {
        System.out.println("1");
        myIterfece.test();
        System.out.println("2");
    }

    public static void main(String[] args) {
        Test2 test2 = new Test2();
        test2.meTest(new MyIterfece() {
            @Override
            public void test() {
                System.out.println("mytest");
            }
        });
        /*
        当函数式接口里的方法没有参数时 ()不能省略
        因为函数式接口只有一个抽象方法 所以方法名就不那么重要
         */

        test2.meTest(() -> System.out.println("mytest"));

        System.out.println("====================================");

        //等同于MyIterfece接口实现类
        MyIterfece myIterfece = () -> System.out.println("mytest");

        System.out.println(myIterfece.getClass());
        System.out.println(myIterfece.getClass().getSuperclass());
        //打印该实现类实现的接口
        System.out.println(myIterfece.getClass().getInterfaces()[0]);
    }


}

打印结果

/*
1
mytest
2
1
mytest
2
====================================
MyIterfece接口的实现类
class com.shengsiyuan.jdk8.Test2$$Lambda$2/1603195447
实现类接口的父类
class java.lang.Object
实现类实现的接口
interface com.shengsiyuan.jdk8.MyIterfece

 */

传统外部迭代:通过下标一个一个迭代出数据(for循环 增强for 迭代器)
内部迭代: 从内部以一个取出数据

例3:将集合英文变成大写


public class Test3 {

    public static void main(String[] args) {

//        /*
//            对于lambda表达式来说 完全不用管函数式接口里方法名是什么,因为其实通过上下文进行类型推断
//            只需要关系返回值和参数即可
//         */
//        TheInterface theInterface = () -> {
//        };
//        System.out.println(theInterface.getClass().getInterfaces()[0]);
//
//        TheInterface2 theInterface2 = () -> {
//        };
//        System.out.println(theInterface2.getClass().getInterfaces()[0]);
//
//        //lambda表达式必须依附上下文定位到对应类型 如果没有上下文就会报错
////        ()->{};
//
//
//        new Thread(() -> System.out.println("thread")).start();

        //将集合英文变成大写
        List<String> list = Arrays.asList("hello", "world", "hello world");

//        List<String> list2 = Lists.newArrayList();
//        list.forEach(x -> list2.add(x.toUpperCase()));
//        list2.forEach(x -> System.out.println(x));

        /*
            采用stream流的方式来编写
            map 映射的意思就是将一个值映射为另外一个值
            Stream方法中也有个forEach方法作用类似Iterable接口的forEach
         */
//        list.stream().map(x -> x.toUpperCase()).forEach(y -> System.out.println(y));

        /*
            采用方法引用的方式
            x -> x.toUpperCase() 等价于 String::toUpperCase
         */
        list.stream().map(String::toUpperCase).forEach(System.out::println);

        /*
           Function<String,String>
           输入是调用toString lambda对象的第一个参数 x(也就是String对象) (  x -> x.toUpperCase() 等价于 String::toUpperCase)
           输出是toString方法返回的值

         */
        Function<String, String> function = String::toString;
        System.out.println(function.getClass().getInterfaces()[0]);


    }


    @FunctionalInterface
    interface TheInterface {

        void myMethod();
    }

    @FunctionalInterface
    interface TheInterface2 {

        void myMethod2();
    }
}

例4

public class StringComparator {

    public static void main(String[] args) {
        /*
            集合倒叙排序
         */
        List<String> list = Arrays.asList("zhangsan", "zhaojie", "maliu");

        Collections.sort(list, (x, y) -> x.compareTo(y));
        System.out.println(list);

    }
}

在例三中stream().map(Function<? super T, ? extends R> mapper)
在这里插入图片描述

Function(重要)

 		Function<String,String>
           输入:是调用toString lambda对象的第一个参数 x(也就是String对象) (  x -> 			  x.toUpperCase() 等价于 String::toUpperCase)
           返回:是toString方法返回的值

         */
        Function<String, String> function = String::toString;
        System.out.println(function.getClass().getInterfaces()[0]);
		//map参数就是Function<T,R> 此时 将x当做参数,x.toUpperCase() 当做值返回
 		list.stream().map(x -> x.toUpperCase()).forEach(y -> System.out.println(y));

在这里插入图片描述
例5

public class FunctionTest {

    public static void main(String[] args) {

        FunctionTest functionTest = new FunctionTest();
  
        System.out.println(functionTest.function(5, x -> x * 2));

        /*
            x -> x +2 是一个行为  当调用方法时他将 x +2 这种行为动作传过去
            执行到function.apply(a)时 此时才会执行改行为 执行完返回对应数据
            此时行为是用的时候传过去对应的行为(加减乘除) 
            
         */
        System.out.println(functionTest.function(10, x -> x + 2));
        System.out.println(functionTest.function(10, x -> x * x));


        System.out.println(functionTest.function2(10, x -> x + "你好啊!"));

        //传统方式
        System.out.println(functionTest.method(2));
    }

    //接受一个参数和一个行为
    public int function(int a, Function<Integer, Integer> function) {
        Integer apply = function.apply(a);
        return apply;
    }

    public String function2(int a, Function<Integer, String> function) {
        String apply = function.apply(a);
        return apply;
    }

    /*
        传统方法,我们需要提前将行为定义好 再去调用对应的方法
        在运行之前行为都是定义好的做不到灵活多变

     */
    public int method(Integer a) {
        return a * 5;
    }

    public int method2(Integer a) {
        return a + 2;
    }

    public int method3(Integer a) {
        return a * a;
    }
}
10
12
10你好啊!

Function中两个默认方法 一个静态方法

	/*
		总是返回始终返回调用方
		其输入参数的函数
	*/
	 static <T> Function<T, T> identity() {
	        return t -> t;
	    }
	/*
		组合函数 将传过来的Function行为apply执行结果 当做第二个Function的行为的执行参数 
		返回apply结果
	*/
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));//返回结果
    }

    /**
    	组合函数 与上面相反 是将当前的Function行为apply执行结果 当做传过来Function的行为的执行参数
    	返回apply结果
     */
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        //t = 当前Function调用andThen的对象行为 
        return (T t) -> after.apply(apply(t));
    }

例6

	
        Function<String, String> function3 = y -> y + "1";


        Function<String, String> function2 = x -> x + "nihao";
        //将String对象 传过去
        Function<String, String> andThen = function2.andThen(function3);
        Function<String, String> compose = function2.compose(function3);
		//返回结果根据用户传过来的的行为决定 ,参数再去执行对应的行为
        String andThenapply = andThen.apply("22");
        System.out.println(andThenapply); 

        System.out.println("=======================================");

        String composeapply = compose.apply("22");
        System.out.println(composeapply);

打印结果

22nihao1 
=======================================
221nihao//先执行y -> y + "1".apply("22") 得到的结果221 在执行 x -> x + "nihao".apply(221)
原创文章 39 获赞 6 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_42261668/article/details/106062693