深入Lambda

深入Lambda

(day19)

 

今日内容:

一:函数式接口

1.什么是函数表达式接口

1)接口中只有一个抽象方法

2)Lambda表达式实现的前提条件是:只能做为函数式接口的实现类对象

3)函数式接口为了封装某一个方法而存在

 举例 : 客户要求定义出一个方法功能, 对两个整数a和b做任意操作

客户1 : 求两数的和

客户2 : 求两数的差

客户3 : 求两数而定乘积

... 无数的客户,要对于这个一个方法实现任意的a和b的两数操作

于是上述案例,不仅仅需要a和b两个整数,还需要对于a和b两个数的处理方式,函数式接口就可以将数据的处理方法封装起来,从而将函数式接口作为方法参数进行传递。

二:JDK8中四种函数式接口

1.消费型接口

Consumer<T>

     void accept(T t);

在java中消费概念就是使用参数t

如果需要传递对于数据的消费方式,处理方式,那么Consumer可以作为方法的参数传递

public class Demo01_消费型接口 {

	public static void main(String[] args) {
		// 1.使用lambda表达式作为函数式接口Consumer的一个实现类对象
		// 客户1:花了500,买了一把大宝剑
		Consumer con = a -> System.out.println("客户花了" + a + "买了一把大宝剑");
		testConsumer(500, con);
		// 客户1:花了600,买了一堆化妆品
		Consumer con1 = b -> System.out.println("客户花了" + b + "买了一堆化妆品");
		testConsumer(600, con1);

	}

	/*
	 * 定义出一个方法功能, 客户消费500元现金, 每一个客户消费方法不同 
	 * 1)客户1 : 花了500元, 买了一把大宝剑 
	 * 2)客户2 : 花了500元,买了一堆化妆品 
	 * 3)客户3 : 花了500元, 买了一双球鞋 
	 * 4)客户4 : 花了500元, 捐献 
	 * 5)还有无数的客户,对于500元消费各不相同
	 */

	/*
	 * 分析:
	 * 1.将客户消费金额作为第一个参数 int money
	 * 2.客户数量很多,每一个客户对于钱的消费方式不同,提供对于钱的消费方式
	 */
	public static void testConsumer(int money, Consumer<Integer> con) {
		//Consumer接口中,只有一个抽象方法accept(T t):方法就是为了消费参数t
		con.accept(money);
	}

}

 

2.供给型接口

Supplier<T>

    T get();

方法功能主要产出一个T类型的数据,如果没有方法的参数列表,但是需要获取到指定的结果类型T,那么Supplier接口可以作为方法参数传递

public class Demo02_供给型接口 {

	public static void main(String[] args) {
		//客户1:装5个数据,30~80之间的随机数
		Supplier<Integer> sup = ()->{
			Random ran = new Random();
			Integer k = ran.nextInt(51)+30;
			return k;
		};
		ArrayList list1 = getSupplier(5,sup);
		System.out.println(list1);
		//客户2:装8个数据,1~100之间的随机偶数
		Supplier<Integer> sup1 = ()->{
			Random ran1 = new Random();
			while(true) {
				Integer s = ran1.nextInt(100)+1;
			if(s%2==0) {
					return s;
			}		
			}
		};
		ArrayList list2 = getSupplier(8,sup1);
		System.out.println(list2);

	}
	/* 定义出一个方法功能, 能给客户返回ArrayList<Integer>容器,中装有数据. 容器中装集合数据,由客户决定; 
	* 容器中承装数据有什么规律, 由客户决定;
	1)客户1 : 装5个数据, 30-80之间的随机数
	2)客户2 : 装8个数据, 1-100之间的随机偶数
	3)...*/
	
	/*
	 *分析:
	 *1.第一个方法参数,作为容器中承装的数据个数con 
	 *2.第二个方法参数,需要存储在容器中的整数存在规则
       **/
	public static ArrayList<Integer> getSupplier(int con,Supplier<Integer> sup){
		ArrayList<Integer> list = new ArrayList<>();
		for(int i=0;i<con;i++) {
			//list需要一个Integer类型的数据
			//T get()->T Integer
		list.add(sup.get());
		}
		return list;
	}

}

3.函数型接口

Function<T,R>

    R apply(T t);

1)  R apply(T t)是抽象方法,主要功能是提供一个T类型参数,返回一个R类型结果,如果有一个参数t,需要获取到另外一个结果r,可以将function接口作为方法的参数进行传递

2)  默认方法:andThen(Function<T,R> fun)

将方法调用者Function实现类的计算结果,作为参数fun的T类型参数继续运算。

Function fun1

Function fun2

fun1.andThen(fun2)----->相当于fun2.apply(fun1.apply)

public class Demo03_函数型接口 {

	public static void main(String[] args) {
		/*定义一个方法功能, 根据整数x,获取出对应的整数y, y数据的获取方式由客户决定
		1)客户1 : y 为x的2倍
		2)客户2 : y 与 x 相等
		3)客户3 : y 为 x 的平方
		4)....*/
		
		//客户1 : y 为x的2倍
		Function<Integer,Integer> fun = x->x*2;
		System.out.println(getFunction(10,fun));
		//客户2 : y 与 x 相等
		Function<Integer,Integer> fun1 = x->x;
		System.out.println(getFunction(10,fun1));
		//客户3 : y 为 x 的平方
		Function<Integer,Integer> fun2 = x->x*x;
		System.out.println(getFunction(10,fun2));
		
		System.out.println("我是分割线------------------------------------------------");
		/*案例2:
		定义一个方法功能, 给出一个字符串s, 需要将字符串转成对应的整数, 
		转换之后通过计算获取到另外一个整数y, y数据的计算方式由客户决定(结合使用andThen方法功能)
		1)客户1 : 将”6”, 得到”6”的3倍
		2)客户2 : 将”-2”, 得到-2 + 1 
		3)...*/
		Function<String,Integer> fuun = s->Integer.parseInt(s);
		Function<Integer,Integer> fuun2 = s->s*3;
		System.out.println(getFunction2("6",fuun,fuun2));
	}
	
	/*
	 * 分析:
	 * 1.方法第一个参数表示目前具有整数t
	 * 2.方法第二个参数,需要目标结果y计算方式,根据t得出对应计算结果
	 */
	public static int getFunction(int t,Function<Integer,Integer> fun){
	return	fun.apply(t);
	}
	
	public static int getFunction2(String s,Function<String,Integer> fuun,Function<Integer,Integer> fuun2) {
		//fuun获取到的计算结果Integer类型,作为fuun2的apply的方法参数
		return fuun.andThen(fuun2).apply(s);
		
	}
		
}

4.断言型接口(由于自己也没有达到了解的程度,所以此模块暂时不写)

Predicate<T>

    boolean test(T t);

三:可变参数

如果定义一个方法功能时:参数类型确定,参数个数不确定,可以在方法的参数列表上设计出可变参数(参数的个数可变)

public class Demo05_可变参数 {

	public static void main(String[] args) {
		// 1. 可变参数可以是0个参数
		System.out.println(getSum());  //空
		// 2. 可变参数可以是1个参数
		System.out.println(getSum(5));  //5
		// 3. 可变参数可以是多个参数
		System.out.println(getSum(5,6,7,8)); //26
		
		// 4. 3表示变量s; 4和5表示可变参数is
		System.out.println(getSum1(3,4,5));//9

	}
	//1)一个方法的参数列表中,最多只能有一个可变参数
	public static int getSum(int...is) {
		// is作为一个int[]数组使用
		int sum = 0;
		for(int s : is) {
			 sum = sum+s;
		}
		return sum;
	}
	//2)可变参数必须放置在参数列表的最后
	public static int getSum1(int i,int...is) {
		int sum = 0;
		for(int s : is) {
			 sum = sum+s;
		}
		return sum;
	}

}

四:方法引用

1:函数式接口:

使用Lambda表达式进行实现,如何Lambda表达式的方法体已经被某个对象中的方法实现过,不需要再Lambda表达式中再次实现相同的功能,只需要引用对应已经实现的方法即可,称为方法引用

2:方法引用语法结构:

函数式接口  变量名 = 类对象  :: 方法名;

函数式接口  变量名 = 类名  :: 方法名;

public class Demo06_方法引用 {

	public static void main(String[] args) {
		// 1.使用Lambda表达式实现函数式接口PrintInter
		PrintInter pi = s -> System.out.println(s);
		pi.print("??????");

		// 2.使用方法引用实现函数式接口:方式1
		PrintInter pi2 = System.out::println;
		pi2.print("大大的疑惑");

		/*
		 * 3.使用Lambda表达式实现函数式接口PrintInter
		 *  要求 : 实现过程需要满足 
		 *  1) 将参数String类型转换成int类型
		 *  2)将int类型+1进行输出
		 */
		PrintInter pi3 = s -> {
			int num = Integer.parseInt(s);
			System.out.println(num + 1);
		};
		pi3.print("13");
		

		//4.变形,使用方法引用方式代替原有Lambda表达式语法结构
		PrintInter pi4 = new PrintClass()::print;
		pi4.print("90");
		// new printFirst :: print;

		//5.使用方法引用方式代替原有Lambda表达式语法结构(静态)
		PrintInter pi5 = PrintClass2::print;
		pi5.print("12345");

	}

}

class PrintClass {
	public void print(String s) {
		int num = Integer.parseInt(s);
		System.out.println(num + 1);
	}
}

class PrintClass2 {
	public static void print(String s) {
		int num = Integer.parseInt(s);
		System.out.println(num + 1);
	}
}

@FunctionalInterface
interface PrintInter {
	void print(String s);
}

 

五:StreamingAPI

1.只能用于Connection单列集合

 stream():获取到集合对应的流资源,方法返回值类型Stream接口,证明方法实际返回的是接口的一个实现类方法。

Stream接口:流资源,主要功能就是对单列集合做数据的操作,因此对于集合数据中的操作封装了方法功能。

2.Stream类型中的方法功能:

1)filter(Predicate pre):

表示过滤器,做数据的筛选,通过参数pre断言型接口给出的规则进行数据筛选,返回值类型Stream,方法调用之后可以进行链式调用。

2)forEach(Consumer con):

表示遍历,遍历的方式就是参数消费型接口对于元素的消费方式,返回值类型void

3)count:

表示将目前流资源中操作的数据个数获取到,返回值类型long

4)limit(long size):

方法功能表示截取流资源中的一部分数据,截取保留流资源中从1~size的元素,返回值类型Stream类型

5)skip(long n):

跳过流资源中的n个元素,继续从n之后的元素进行操作,返回值类型Stream类型

6)map(Function<T,R> fun):

将流资源中的所有T类型数据,全部转换成R类型数据,返回值类型Stream类型

public class Demo01_Stream方法使用 {

	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("蓝忘机");
		list.add("蓝启仁");
		list.add("蓝湛");
		list.add("魏无羡");
		list.add("花城");

		// 1.先将集合name对应的Stream流资源获取到
		// filter 中的参数列表 : Predicate断言型接口, 方法调用需要传递实际参数可以使用Lambda表达式实现
		// s表示集合中的每一个字符串,filter本身返回一个Stream类型
		// 获取打印集合中第一个字符是“蓝”,字符长度是3的数据元素
		list.stream().filter(s -> s.startsWith("蓝") && s.length() == 3).forEach(s -> System.out.println(s));// 蓝忘机 蓝启仁

		// 3)count: 表示将目前流资源中操作的数据个数获取到,返回值类型long
		// 获取目前流资源中操作的数据个数
		System.out.println(list.stream().count()); // 5

		
		// 4)limit(long size): 方法功能表示截取流资源中的一部分数据,截取保留流资源中从1~size的元素,返回值类型Stream类
		// 显示在下标3之前的符合要求的数据
		list.stream().limit(3).filter(s -> s.startsWith("蓝") && s.length() == 3).forEach(s -> System.out.println(s));// 蓝忘机
																														// 蓝启仁
	
		
		
		// 5)skip(long n):跳过流资源中的n个元素,继续从n之后的元素进行操作,返回值类型Stream类型
		list.stream().skip(2).filter(x -> x.startsWith("蓝") && x.length() == 3).forEach(System.out::println); // 空
		
		
		
		// 6)map(Function<T,R> fun):将流资源中的所有T类型数据,全部转换成R类型数据,返回值类型Stream类型
         //这个是同类型转换
		list.stream().map(x -> x + 1).forEach(System.out::println);
		// 蓝忘机1 蓝启仁1 蓝湛1 魏无羡1 花城1

	}

}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值