Day_27 Lambda表达式、函数式接口

一、Lambda

  1.  概述
    1. Lambda表达式是一种没有名字的函数,也可称为闭包,是Java 8 发布的最重要新特性。
    2. 本质上是一段匿名内部类,也可以是一段可以传递的代码。
    3. 还有叫箭头函数的...
  2.  为什么使用Lambda表达式
    1. Lambda表达式就是一个匿名内部类的简写方式
    2. 使程序更加简洁清晰,编程效率也得到了提高
  3.  和匿名内部类对比
    1. //  匿名内部类
      		forEach(arr, new Array() {
      			@Override
      			public void m1(int i) {
      				System.out.println(i + "-====-");
      			}
      		});
      //  lambda表达式
      		forEach(arr, (i) -> System.out.println(i + "++++++++++"));
  4. 语法结构
    1. 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
    2. 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。

    3. 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。

      如果不写{}  return 不能写  分号不能写

    4. 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值

      1. 如果只有一条语句,并且是返回值语句,就可以不写return 不写 {} 

      2. 如果写上{}  就必须写return 和 ;

      3. 如果有 多条语句,必须写{}  return 和 ;  也必须写

  5. 案例
    1. 不需要参数,返回值为5

      ()-> 5

    2. 接收一个参数(数字类型),返回其2倍的值 

      x -> x*2

    3. 接受2个参数(数字),并返回他们的差值 

      (x,y)-> x-y

  6. 练习
    1. public class _02_Lambda {
      	public static void main(String[] args) {
      		List<Integer> list = new ArrayList<Integer>();
      		list.add(1);
      		list.add(2);
      		list.add(3);
      		// 常规写法
      		// for (Integer integer : list) {
      		// System.err.println(integer);
      		// }
      
      		// 匿名内部类写法
      		// list.forEach(new Consumer<Integer>() {
      		// @Override
      		// public void accept(Integer t) {
      		// System.out.println(t);
      		// }
      		// });
      		
      		// lambda写法
      		list.forEach(x -> System.out.println(x));
      	}
      }
      	public static void main(String[] args) {
      		List<Integer> list = new ArrayList<Integer>();
      		list.add(11);
      		list.add(2);
      		list.add(3);
      		// Collections.sort(list, new Comparator<Integer>() {
      		// @Override
      		// public int compare(Integer o1, Integer o2) {
      		// return o2-o1;
      		// }
      		// });
      
      		Collections.sort(list, (x, y) -> y - x);
      
      		System.out.println(list);
      	}

二、函数式接口

  1.  介绍
    1. 英文称为Functional Interface

    2. 其本质是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。

    3. 核心目标是为了给Lambda表达式的使用提供更好的支持,进一步达到函数式编程的目标,可通过运用函数式编程极大地提高编程效率。

    4. 其可以被隐式转换为 lambda 表达式。

  2. 特点
    1. 函数式接口是仅制定一个抽象方法的接口

    2. 可以包含一个或多个静态或默认方法

    3. 专用注解即@FunctionalInterface 检查它是否是一个函数式接口,也可不添加该注解

    4. 如果有两个或以上 抽象方法,就不能当成函数式接口去使用,也不能添加@FunctionalInterface这个注解

    5. 如果只有一个抽象方法,那么@FunctionalInterface注解 加不加 都可以当做函数式接口去使用

  3.  代码实现
    1.  无参情况
      1. public class FunInterface_01 {
        	// 自定义静态方法,接收接口对象
        	public static void call(MyFunctionInter func) {
        		// 调用接口内的成员方法
        		func.printMessage();
        	}
        
        	public static void main(String[] args) {
        		// 第一种调用 : 直接调用自定义call方法,传入函数
        		FunInterface_01.call(() -> {
        			System.out.println("HelloWorld!!!");
        		});
        
        		// 第二种调用 : 先创建函数对象,类似于实现接口的内部类对象
        		MyFunctionInter inter = () -> {
        			System.out.println("HelloWorld2!!!!");
        		};
        		// 调用这个实现的方法
        		inter.printMessage();
        	}
        }
        // 函数式接口
        @FunctionalInterface
        interface MyFunctionInter {
        	void printMessage();
        }
        
    2. 有参情况
      1. public class FunInterface_02 {
        	// 自定义静态方法,接收接口对象
        	public static void call(MyFunctionInter_02 func, String message) {
        		// 调用接口内的成员方法
        		func.printMessage(message);
        	}
        
        	public static void main(String[] args) {
        		// 调用需要传递的数据
        		String message = "有参函数式接口调用!!!";
        
        		// 第一种调用 : 直接调用自定义call方法,传入函数,并传入数据
        		FunInterface_02.call((str) -> {
        			System.out.println(str);
        		}, message);
        
        		// 第二种调用 : 先创建函数对象,类似于实现接口的内部类对象
        		MyFunctionInter_02 inter = (str) -> {
        			System.out.println(str);
        		};
        		// 调用这个实现的方法
        		inter.printMessage(message);
        	}
        }
        
        // 函数式接口
        @FunctionalInterface
        interface MyFunctionInter_02 {
        	void printMessage(String message);
        }
        

    3. JDK自带常用的函数式接口
      1.  Supplier<T>接口
        1. Supplier<T>接口    代表结果供应商,所以有返回值,可以获取数据

          有一个get方法,用于获取数据

        2. public class _03_JdkOwn_01 {
          	private static String getResult(Supplier<String> function) {
          		return function.get();
          	}
          
          	public static void main(String[] args) {
          		// 1
          		String before = "张三";
          		String after = "你好";
          		// 把两个字符串拼接起来
          		System.out.println(getResult(() -> before + after));
          
          		// 2 //创建Supplier容器,声明为_03_JdkOwn类型
          		// 此时并不会调用对象的构造方法,即不会创建对象
          		Supplier<_03_JdkOwn_01> sup = _03_JdkOwn_01::new;
          		_03_JdkOwn_01 jo1 = sup.get();
          		_03_JdkOwn_01 jo2 = sup.get();
          
          	}
          
          	public _03_JdkOwn_01() {
          		System.out.println("构造方法执行了");
          	}
          }
          
      2. Consumer<T>接口
        1. Consumer<T>接口    消费者接口所以不需要返回值

          有一个accept(T)方法,用于执行消费操作,可以对给定的参数T 做任意操作

        2. public class _04_JdkOwn_02 {
          	private static void consumeResult(Consumer<String> function, String message) {
          		function.accept(message);
          	}
          
          	public static void main(String[] args) {
          		// 传递的参数
          		String message = "消费一些内容!!!";
          		// 调用方法
          		consumeResult(result -> {
          			System.out.println(result);
          		}, message);
          	}
          }
          
      3. Function<T,R>接口
        1. Function<T,R>接口  表示接收一个参数并产生结果的函数

          顾名思义,是函数操作的

          有一个R apply(T)方法,Function中没有具体的操作,具体的操作需要我们去为它指定,因此apply具体返回的结果取决于传入的lambda表达式

        2. public class _05_JdkOwn_03 {
          	// Function<参数, 返回值>
          	public static void convertType(Function<String, Integer> function,
          			String str) {
          		int num = function.apply(str);
          		System.out.println(num);
          	}
          
          	public static void main(String[] args) {
          		// 传递的参数
          		String str = "123";
          		// s是说明需要传递参数, 也可以写 (s)
          		convertType(s -> {
          			int sInt = Integer.parseInt(s);
          			return sInt;
          		}, str);
          	}
          }
          

      4. Predicate<T>接口
        1. Predicate<T>接口   断言接口

          就是做一些判断,返回值为boolean

          有一个boolean test(T)方法,用于校验传入数据是否符合判断条件,返回boolean类型

        2. public class _06_JdkOwn_04 {
          	// 自定义方法,并且 Predicate 接收String字符串类型
          	public static void call(Predicate<String> predicate, String isOKMessage) {
          		boolean isOK = predicate.test(isOKMessage);
          		System.out.println("isOK吗:" + isOK);
          	}
          
          	public static void main(String[] args) {
          		// 传入的参数
          		String input = "ok";
          		call((String message) -> {
          			// 不区分大小写比较,是ok就返回true,否则返回false
          			if (message.equalsIgnoreCase("ok")) {
          				return true;
          			}
          			return false;
          		}, input);
          	}
          }
          

    4. 方法引用和构造器调用
      1. 对象调用成员
        1. 对象引用::成员方法名
          要求 : 需要根据调用方法的入参和出参去选择对应的函数式接口才行
        2. public static void main(String[] args) {
          		Integer i1 = new Integer(123);
          		// 常规lambda写法
          		Supplier<String> su = () -> i1.toString();
          		System.out.println(su.get());
          
          		// 方法引用写法
          		su = i1::toString;
          		System.out.println(su.get());
          	}
      2. 类名调用静态
        1. 类名::静态
        2. public class _02_FunCall {
          	public static void main(String[] args) {
          
          		Function<String, Integer> fun = Integer::parseInt;
          		System.out.println(fun.apply("123"));
          
          		fun = new Function<String, Integer>() {
          			@Override
          			public Integer apply(String t) {
          				// TODO Auto-generated method stub
          				return null;
          			}
          		};
          
          		fun = x -> Integer.parseInt(x);
          		fun = Integer::parseInt;
          
          		// 前两个是入参,第三个是返回值
          		BiFunction<Integer, Integer, Integer> bif = Integer::max;
          		System.out.println(bif.apply(123, 323));
          		test((B x) -> System.out.println(x));
          	}
          
          	public static void test(A a) {
          
          	}
          }
          
          interface A {
          	public void m1(B b);
          }
          
          class B {
          
          }
          
      3. 类名调用成员
        1. 类名::成员方法名
        2. public static void main(String[] args) {
          		BiPredicate<String, String> bp = String::equals;
          		System.out.println(bp.test("abc", "abc"));
          	}
      4. 构造方法调用
        1. public static void main(String[] args) {
          		// 无参构造
          		Supplier<Object> objSi = Object::new;
          		System.out.println(objSi.get());
          
          		// 有参构造
          		Function<String, Integer> function = Integer::new;
          		System.out.println(function.apply("123"));
          		// new Integer("123");
          	}
      5. 数组引用
        1. public static void main(String[] args) {
          		Function<Integer, Integer[]> function = Integer[]::new;
          		Integer[] arr = function.apply(10);
          		
          		for (Integer integer : arr) {
          			System.out.println(integer);
          		}
          	}

三、Stream API

  1.  概念说明
    1. 数据渠道、管道,用于操作数据源(集合、数组等)所生成的元素序列。

    2. 集合讲的是数据,流讲的是计算

    3. 即一组用来处理数组,集合的API。

  2. 特点
    1. Stream 不是数据结构,没有内部存储,自己不会存储元素。

    2. Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

    3. Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

    4. 不支持索引访问。

    5. 延迟计算

    6. 支持并行

    7. 很容易生成数据或集合

    8. 支持过滤,查找,转换,汇总,聚合等操作。

  3. 应用场景
    1. 流式计算处理,需要延迟计算、更方便的并行计算

    2. 更灵活、简洁的集合处理方式场景

  4. 代码实现
    1.  运行机制说明
      1. Stream分为源source,中间操作,终止操作。

      2. 流的源可以是一个数组,集合,生成器方法,I/O通道等等。

      3. 一个流可以有零个或多个中间操作,每一个中间操作都会返回一个新的流,供下一个操作使用,一个流只会有一个终止操作。

      4. 中间操作也称为转换算子-transformation

      5. Stream只有遇到终止操作,它的数据源会开始执行遍历操作。

      6. 终止操作也称为动作算子-action

      7. 因为动作算子的返回值不再是 stream,所以这个计算就终止了

      8. 只有碰到动作算子的时候,才会真正的计算

    2. 创建流的方式

      1. public static void main(String[] args) {
        		//1 数组转换为流
        		String[] strings = {"q","w","e","r"};
        		Stream<String> stream1 = Stream.of(strings);
        		// 2 通过集合
        		// Arrays.asList : 把数组转换为集合
        		List<String> list = Arrays.asList(strings);
        		stream1 = list.stream();
        		
        		// 3 通过Stream的generate创建
        		// 但是是一个无限流(无限大),所以经常结合limit一起使用,来限制最大个数
        		// generate参数是一个 Supplier ,而 Supplier中有一个get方法用于获取数据
        		// 而 get方法的返回值,会作为数据保存到这个流中,下面程序也就意味中该流中的数据都是1
        		Stream<Integer> stream2 = Stream.generate(()->1);
        		// limit 是中间操作,设置流的最大个数
        		// forEach 遍历,是终止操作
        		stream2.limit(5).forEach(x->System.out.println(x) );
        		
        		// 4 通过String.iterate
        		// 同上,是无限流
        		// 参数1 是起始值, 参数二 是function, 有参有返回值
        		// x+2 等于步长为二  for(int i =1 ; true ; i+=2)
        		Stream<Integer> stream3 = Stream.iterate(1, x->x+2);
        		stream3.limit(10).forEach(x->System.out.println(x));
        		
        		// 5 已有类的API
        		String string = "abc";
        		IntStream chars = string.chars();
        		chars.forEach(x->System.out.println(x));
        	}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值