Java Lambda表达式 、函数式接口 、方法引用和构造器调用 、 Stream

目录

1. Lambda

1.1 概述

1.2 为什么使用Lambda表达式

1.3 和匿名内部类对比

1.4 语法结构

1.5 案例

1.6 练习

2. 函数式接口

2.1 介绍

2.2 特点

2.3 代码实现

2.3.1 无参情况

2.3.2 有参情况

2.4 JDK自带常用的函数式接口

2.4.1Supplier 接口

2.4.2Consumer 接口

2.4.4 Predicate 接口

3. 方法引用和构造器调用

3.1对象调用成员

3.2类名调用成员 

3.3类名调用成员

3.4构造方法调用

3.5数组引用

4. StreamAPI

4.1 概念说明

4.2特点

4.3应用场景

4.4代码实现  

4.4.1 运行机制说明

4.4.2创建流的方式

4.4.3 常见中间操作

4.4.4 常见的终止操作


1. Lambda

1.1 概述

Lambda 表达式是一种没有名字的函数,也可称为闭包,是Java 8 发布的最重要新特性。

本质上是一段匿名内部类 , 也可以是一段可以传递的代码

还有叫箭头函数的....

1.2 为什么使用Lambda表达式

Lambda表达式就是一个匿名内部类的简写方式

使程序更加简介清晰,编程效率也得到了提高

1.3 和匿名内部类对比

package _01_Lambda;


public class _01_Lambda {

	public static void main(String[] args) {
		int[] arr = {1,2,3,4};
		//常规遍历
		for(int j: arr){
			System.out.println(j);
		}
		
		//1. 实现类
		forEach(arr , new A());
		//2. 匿名内部类
		forEach(arr, new Array(){
			@Override
			public void m1(int i ){
				System.out.println(i+"=========");
			}
			
		});
		//3. Lambda 表达式
		forEach(arr , (i)->System.out.println(i+1+"000000000"));
		
	}
	//封装的功能,完成遍历操作,但是需要传递数组,和要做的事情
	private static void forEach(int[] arr, Array array) {
		for(int i :arr){
			array.m1(i);
		}
	}
}
//封装要做的事
interface Array{
	void m1(int i );
}
class A implements Array {

	@Override
	public void m1(int i) {
		System.out.println(i+"___________");
	}
	
}

1.4 语法结构

可选类型声明 : 不需要声明参数类型 , 编译器可以统一识别参数值

可选的参数圆括号 : 一个参数无需定义圆括号,但多个参数需要定义圆括号

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

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

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

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

          如果写上{} 就必须写return 和  ; 分号

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

1.5 案例

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

()->5

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

x->x*2

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

(x,y)->x-y

1.6 练习

package _01_Lambda;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class _02_Lambda {

	public static void main(String[] args) {
	List<Integer> list = new ArrayList<Integer>();	
	list.add(1);
	list.add(22);
	list.add(3);
	//遍历
	//常规写法
	for(Integer integer : list){
		System.out.println(integer);
	}
	
	//匿名内部类写法
	list.forEach(new Consumer<Integer>(){
		@Override
		public void accept(Integer t){
			System.out.println(t);
		}
	});
	//Lambda 写法
	list.forEach(q-> System.out.println(q));
	}
}
package _01_Lambda;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class _03_Lambda {

	public static void main(String[] args) {
		List<Integer> list = new ArrayList<Integer>();
		list.add(1);
		list.add(22);
		list.add(711);
		//Lambda 排序  降序排序
		Collections.sort(list, (x,y)->y-x);
		System.out.println(list);
		
		//传统的排序
		Collections.sort(list , new Comparator<Integer>(){

			@Override
			public int compare(Integer o1, Integer o2) {
				return o2-o1;
			}
			
		});
		System.out.println(list);
	}
}
class B{
	@Override
	public boolean equals(Object obj){
		return false;
	}
}

2. 函数式接口

2.1 介绍

英文称为Functional Interface       

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

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

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

2.2 特点

函数式接口是仅制定一个抽象方法的接口

可以包含一个或多个静态或more方法

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

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

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

2.3 代码实现

2.3.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.3.2 有参情况

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

2.4 JDK自带常用的函数式接口

2.4.1Supplier<T> 接口

Supplier<T>接口  代表结果供应商,所以有返回值,可以获取数据

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

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("构造方法执行了");
	}
}
package _02_Functions;

import java.util.function.Supplier;

/**
 * Supplier : 代表供应商,有返回值,可以获取数据使用
 * 
 * 提供一个get方法
 * 
 * @author 人间失格
 * @data     2021年11月2日下午7:08:42
 */
public class _02_Functions {

	public static void main(String[] args) {
		String string = "张三";
		String result = getResult(()->"我是 :"+ string);
		System.out.println(result);
	}
// f封装 完成指定功能
	private static String getResult(Supplier<String>supplier) {
		return supplier.get();
	}
}

2.4.2Consumer<T> 接口

Consumer<T> 接口  消费者接口所以不需要返回值

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

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

package _02_Functions;

import java.util.function.Consumer;

/**
 * Consumer : 代表了消费者,提供了accept方法 有参数 但是无返回值
 * 
 * @author 人间失格
 * @data 2021年11月2日下午6:56:08
 */
public class _01_Functions {

	public static void main(String[] args) {
		int[] arr = { 1, 2, 3, 4, };
		// 常规遍历
		for (int j : arr) {
			System.out.println(j);
		}

		// 3. lambda 表达式
		forEach(arr , (i)->System.out.println(i));
	}
	//封装的功能,完成遍历操作,但是需要传递数组,和要做的事
	//该方法只是帮我们遍历而已
	public static void forEach(int[] arr , Consumer<Integer> c){
		for(int i : arr){
			c.accept(i);
		}
	}
}

2.4.3 FUnction<T,R> 接口

Function<T,R> 接口 , 表示接收一个参数并产生结果的函数

顾名思义,是函数操作的

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

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

import java.util.function.Function;

/**
 * Function : 有参有返回值,提供了apply方法
 * 
 * @author 人间失格
 * @data     2021年11月2日下午7:21:09
 */
public class _03_Functions {
public static Integer m1(String string, Function<String, Integer>fun) {
	return fun.apply(string);
}
	public static void main(String[] args) {
		String string =  "123";
		int result = m1(string , s->Integer.parseInt(s));
		System.out.println(result);
	}

}

2.4.4 Predicate<T> 接口

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

3. 方法引用和构造器调用

3.1对象调用成员

package _03_FunCall;

import java.util.function.Supplier;

/**
 * 对象引用 :: 成员方法名
 * 
 * @author 人间失格
 * @data     2021年11月2日下午7:26:41
 */
public class _01_FunCall {

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

}

3.2类名调用成员 

package _03_FunCall;

import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * 类名 :: 静态
 * 
 * @author 人间失格
 * @data     2021年11月2日下午7:33:41
 */
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) {
				return null;
			}
			
		};
		
		fun = x-> Integer.parseInt(x);
		fun = Integer::parseInt;
		
		//前面两个是入参 , 第三个是返回值
		//类名:: 静态
		BiFunction<Integer , Integer , Integer>bif = Integer :: max;
		
	}
	//静态方法
	public static void test(A a){
		
	}
}
//接口
interface A{
	public void m1(B b);
}
class B{}

3.3类名调用成员

package _03_FunCall;

import java.util.function.BiPredicate;

/**
 * 类名 :: 成员方法名
 * 
 * @author 人间失格
 * @data     2021年11月2日下午7:43:40
 */
public class _03_FunCall {

	public static void main(String[] args) {
		//判断字符串是否相等
	BiPredicate<String ,String>	bp = String::equals;
	System.out.println(bp.test("abc", "abc"));
	}

}

3.4构造方法调用

package _01_Lambda;

import java.util.function.Function;
import java.util.function.Supplier;

public class _04_Constryctarcakk {

	public static void main(String[] args) {
		//无参构造
		Supplier<Object> objSi = Object :: new ;
		System.out.println(objSi.get());
		
		//有参构造
		Function<String , Integer>function = Integer :: new;
		//new Integer("123")
		System.out.println(function.apply("123"));
	}
}

3.5数组引用

package _01_Lambda;

/**
*
* 数组引用
*
*/
import java.util.function.Function;

public class _05_ArrayCall {

	public static void main(String[] args) {
		Function<Integer , Integer[]> function = Integer[] :: new;
		Integer[] arr = function.apply(6);
		
		for(Integer integer : arr){
			System.out.println(integer);
		}
	}

}

4. StreamAPI

4.1 概念说明

数据渠道、管道 , 用于操作数据源(集合、数组等)所生成的元素序列

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

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

4.2特点

Stream 不是数据结构,没有内部存储,自己不会存储元素

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

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

不支持索引访问

延迟计算

支持并行

很容易生成数据或集合

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

4.3应用场景

流式计算处理,需要延迟计算、更方便的并行计算

更灵活、简介的集合处理方式场景

4.4代码实现  

4.4.1 运行机制说明

Stream分为源source , 中间操作,终止操作

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

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

中间操作也称为算子-transformation

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

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

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

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

4.4.2创建流的方式

package _04_Stream;

import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * 生成流
 * 
 * @author 人间失格
 * @data     2021年11月2日下午7:46:11
 */
public class _01_Stream {

	public static void main(String[] args) {
		//1. 数组转换位流
		String[] strings = {"q","w","e","r"};
		Stream<String> streaml = Stream.of(strings);
		System.out.println(streaml);
		//java.util.stream.ReferencePipeline$Head@6d06d69c
		
		
		//2. 通过集合
		//Arrays.asList : 把数组转换位集合
		List<String>list = Arrays.asList(strings);
		streaml=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>streams = Stream.iterate(1, x->x+2);
		streams.limit(10).forEach(x->System.out.println(x));
		
		
		// 5 . 已有类的API
		String string = "abc";
		//string转为char类型  输出值位对应的ASCII值
		IntStream chars = string.chars();
		chars.forEach(x->System.out.println(x));
	}
}

4.4.3 常见中间操作

4.4.3.1概述

一个中间操作链,对数据进行处理,一个流可以有0~N个中间操作

他们每一个都返回新的流,方便下一个进行操作

但是只能有一个终止操作

4.4.3.2 常见中间操作

 * fitter : 对元素进行过滤筛选,不符合的就不要了
 * 
 * distinct : 去掉重复元素
 * 
 * skip :跳过多少元素
 * 
 * limit :取最大条数(前几条)
 * 
 * map : 对集合中的元素进行遍历操作
 * 
 * sorted : 排序

4.4.3.3 常见异常

 Stream使用之后,必须生成新的流,不能使用原来的stream

所以可以进行链式调用,因为中间操作返回值都是一个新的stream

4.4.3.4 使用方式

package com;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 一个中间操作链,对数据进行处理,一个流可以有0~N个中间操作
 * 
 * 他们每一个都返回新的流,方便下一个进行操作
 * 
 * 但是只能有一个终止操作
 * 
 * fitter : 对元素进行过滤筛选,不符合的就不要了
 * 
 * distinct : 去掉重复元素
 * 
 * skip :跳过多少元素
 * 
 * limit :取最大条数(前几条)
 * 
 * map : 对集合中的元素进行遍历操作
 * 
 * sorted : 排序
 * 
 * @author 人间失格
 * @data     2021年11月3日下午6:41:55
 */
public class Stream_01 {

	public static void main(String[] args) {
		//创建集合,Array.asList将一个数组转换为List集合  asList方法返回的ArrayList数组
	List<String>strings = Arrays.asList("a","b","c","a");
	//将集合转换成流
	Stream<String> stream = strings.stream();
//	stream.filter(x->false);
	//Stream使用之后,必须生成新的流,不能使用原来的stream
	//所以可以进行链式调用,因为中间操作返回值都是一个新的stream
	/**
	 * filter : 对元素进行过滤筛选,不符合的就不要了
	 */
	//x->!x.equals("a") : 如果返回false,就不要该数据了,如果返回true,就要该数据
	//collect(Collectors.toList()) : 终止操作,把stream转换为集合
		List<String >value = stream.filter(x->!x.equals("a")).collect(Collectors.toList());
		System.out.println(value);
		
		/**
		 * skip : 跳过 本来是abca跳过两个还剩下ca
		 */
		//需要重新生成流
		stream  =strings.stream();
		value = stream.skip(2).collect(Collectors.toList());
		System.out.println(value);
		
		/**
		 * map: 对集合中的元素进行遍历并操作
		 */
		List<Integer>list = Arrays.asList(1000,1200,1100,900,5500);
		Stream<Integer>stream2 = list.stream();
		//涨薪百分之十
		List<Integer>result = stream2.map(x->x+x/10).collect(Collectors.toList());
		System.out.println(result);
		
		/**
		 * distomct :去除重复
		 */
		stream = strings.stream();
		value = stream.distinct().collect(Collectors.toList());
		System.out.println(value);
		
		/**
		 * limit : 前几条
		 * 
		 * 本来是abcd 前两条是ab
		 */
		stream = strings.stream();
		value = stream.limit(2).collect(Collectors.toList());
		System.out.println(value);
		
		/**
		 * sorted : 排序
		 */
//		stream2 = list.stream();
//		result = stream2.sorted((x,y)->y-x).collect(Collectors.toList());
//		System.out.println(result);
		
		//匿名内部类写法 更改为降序排序
		stream2 = list.stream();
		 result = stream2.sorted(new Comparator<Integer>() {
				 @Override
				 public int compare(Integer o1, Integer o2) {
				 return o2-o1;
				 }
				 }).collect(Collectors.toList());
		 System.out.println(result);
	}
}

4.4.4 常见的终止操作

4.4.4.1 概述

一旦执行终止操作,中间操作才会真正执行 并且stream也就不能再被使用了

4.4.4.2 常见的终止操作

 * forEach : 遍历
 * 
 * collect : 收集器
 * 
 * min,max,count,agerage 计算相关
 * 
 * asyMatch :匹配数据,比如是否包含

4.4.4.3 使用方式

package com;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

/**
 * 一旦执行终止操作,中间操作才会真正执行,并且stream也就不能再被使用了
 * 
 * forEach : 遍历
 * 
 * collect : 收集器
 * 
 * min,max,count,agerage 计算相关
 * 
 * asyMatch :匹配数据,比如是否包含
 * 
 * @author 人间失格
 * @data     2021年11月3日下午7:34:39
 */
public class Stream_02 {

	public static void main(String[] args) {
		List<String> strings = Arrays.asList("a","b","c","a","c","a");
		Stream<String> stream =strings.stream();
		//forEach
		stream.limit(3).forEach(x->System.out.println(x));
		
		stream = strings.stream();
		//获取条数,这种不如直接调用集合中的size方法更加的简单一些
		long count  =stream.count();
		System.out.println(count);
		//所以,这样很难体现出count的优势,一般需要结合中间操作执行,优势更大
		//例如 统计有多少个a
		stream = strings.stream();
		//filter : 对元素进行筛选
		count = stream.filter(x->x.equals("a")).count();
		System.out.println(count);
		
		//获取最大值max
		List<Integer> integers =Arrays.asList(1,2,3,4,5);
		Stream<Integer>stream2=integers.stream();
		Integer i1 = stream2.max((x,y)->x-y).get();
		System.out.println(i1);
		
		//匹配数据 anyMatch
		stream2 = integers.stream();
		boolean flag = stream2.anyMatch(x->x==0);
		System.out.println(flag);
		//上面 这种使用集合的contains也可以解决,但是也有contains解决不了的问题
		System.out.println(integers.contains(5));
		
		//比如好多学生 判断是否有19岁的学生,使用contains的话,Student中就要覆写equals方法了
		List<Student>students = new ArrayList<Student>();
		students.add(new Student("张一", 18));
		students.add(new Student("张二", 19));
		students.add(new Student("张三", 17));
		students.add(new Student("张四", 18));
		students.add(new Student("张五", 19));
		students.add(new Student("张六", 20));
		students.add(new Student("张七", 21));
		Stream<Student>stream3= students.stream();
		flag = stream3.anyMatch(a->a.age==19);
		System.out.println(flag);

	}
}
class Student{
	String name;
	int age;
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}	
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Iiversse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值