day_25Lambda表达式、函数式接口

1. Lambda

1.1概述

Lambda表达式是一种没有名字的函数,也可以称为闭包.是java8发布的最重要的新特性.本质上是一段匿名内部类,也可以是一段可以传递的代码.

还有叫箭头函数的

1.2为什么使用Lambda表达式

Lambda表达式就是个匿名内部类的简写方式,使程序更加简单清晰,编程效率也得到了提高

1.3和匿名内部类对比

		//2匿名内部类
		forEach(arr,new Array(){
			
			public void m1(int i){
				System.out.println(i +"-===-");
			}
		});
		//3Lambda表达式
		forEach(arr,(i)->System.out.println(i+1+"+++"));

1.4语法结构

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

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

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

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

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

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

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

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

1.5案例

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

()->5

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

x->x*2

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

(x,y)->x-y

1.6练习

package day_27text;

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

public class Text02 {

	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>(){
		//public void accept(Integer t){
		//System.out.println(t);
		//}
		//});
		
		//Lambda写法
		list.forEach(x->System.out.println(x));
	}

}
package day_27text;

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

public class Text03 {

	public static void main(String[] args) {
		List<Integer>list = new ArrayList<Integer>();
		list.add(11);
		list.add(2);
		list.add(3);
		//Cillections.sort(list,new Comparator<Integer>(){
		//public int compare(Inreger o1,Integer o2){
		//return o2 - o1;
		//}
		//});
		
		Collections.sort(list,(x,y) -> y - x);
		
		System.out.println(list);
	}

}
class B{
	public boolean equals(Object obj){
		return false;
	}
}

2.函数式接口

2.1介绍

        应为称为Functional Interface

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

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

        其可以被隐式转换为Lambda表达式.

2.2特点

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

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

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

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

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

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.4JDK自带常用的函数式接口

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

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

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

2.4.4Predicate<T>接口

Predicate<T>接口 断言接口

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

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

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.方法引用和构造器调用

2.5对象调用对象

package day_27text03;

import java.util.function.Supplier;

/**
 * 对象引用::成员方法名
 * 
 * 要求 : 需要根据调用方法的入参和出参去选择对应的函数式接口才行
 *
 * @author 学到头秃的张张张
 *@Date 2021年11月3日上午3:15:19
 */
public class Text01 {
	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.6类名调用静态

package day_27text03;

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

/**
 *类名::静态
 *
 * @author 学到头秃的张张张
 *@Date 2021年11月3日上午3:17:09
 */
public class Text02 {
	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 {

}

2.7类名调用对象

package day_27text03;

import java.util.function.BiPredicate;

/**
 * 类名::成员方法名
 *
 * @author 学到头秃的张张张
 *@Date 2021年11月3日上午3:22:42
 */
public class Text03 {
	public static void main(String[] args) {
		BiPredicate<String, String> bp = String::equals;
		System.out.println(bp.test("abc", "abc"));
	}
}

2.8构造方法调用

package day_27text;

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

public class Text04 {

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

	}

}

2.9数组引用

package day_27text;

import java.util.function.Function;

public class Text05 {

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

	}

}

4.Stream API

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

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

/**
 * 生成流
 *
 * @author 学到头秃的张张张
 *@Date 2021年11月3日上午3:37:07
 */
public class Text01 {
	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));
	}
}

4.4.3常见中间操作

4.4.3.1概述

 * 一个中间操作链,对数据进行处理,一个流可以有0~N个中间操作
 * 
 * 他们每一个都返回新的流,方便下一个进行操作
 * 
 * 但是只能有一个终止操作

4.4.3.2常见中间操作

/** 
 * filter:对元素进行过滤筛选,不符合的就不要了
 * 
 * distinct:去掉重复元素
 * 
 * skip:跳过多少元素
 * 
 * limit:取最大的条数(前几条)
 * 
 * map:对集合中的元素进行便利操作
 * 
 * sorted:排序
 *
 * @author 学到头秃的张张张
 *@Date 2021年11月4日上午1:39:39
 */

4.4.3.3常见异常

 

//Stream使用之后,必须生成新的流,不能使用原来的Stream
//所以可以进行链式调用,因为中间操作返回值都是一个新的Stream
//Stream.filter(x->false)

4.4.3.4使用方式

package day_28text;

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

public class Text01 {

	public static void main(String[] args) {
		List<String> strings = Arrays.asList("a","b","c","a");
		Stream<String> stream = strings.stream();
		//stream.filter(x->false);
		//Stream使用之后,必须生成新的流,不能使用原来的stream
		//所以可以进行链式调用,因为中间操作返回值都是一个新的stream
		//stream.filter(x->false);
		/**
		 * 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(100,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);
		/**
		 * distinct:去除重复
		 */
		stream = strings.stream();
		value=stream.distinct().collect(Collectors.toList());
		System.out.println(value);
		/**
		 * limit:前几条
		 * 
		 * 本来是abca 前两条是[a,b]
		 */
		stream = strings.stream();
		value = stream.limit(2).collect(Collectors.toList());
		System.out.println(value);
		/**
		 * sorted : 排序
		 */
		stream2 = list.stream();
		// [900, 1000, 1100, 1200, 5500] 默认升序
		// result = stream2.sorted().collect(Collectors.toList());		
		// 匿名内部类  更改为降序
		// [5500, 1200, 1100, 1000, 900]
		// result = stream2.sorted(new Comparator<Integer>() {
		// @Override
		// public int compare(Integer o1, Integer o2) {
		// return o2-o1;
		// }
		// }).collect(Collectors.toList());
		// lambda写法	
		result = stream2.sorted((x, y) -> y - x).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 计算相关
 * 
 * anyMatch 匹配数据,比如是否包含
 *
 * @author 学到头秃的张张张
 *@Date 2021年11月4日上午2:15:29
 */

3.4.4.3使用方式

package day_28text;

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

public class Text02 {
	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(2).forEach(x->System.out.println(x));
		
		stream = strings.stream();
		// 获取条数,这种不如直接调用集合的size方法简单一些
		long count = stream.count();
		System.out.println(count);
		// 所以 这样很难体现出count的优势,一般需要结合中间操作执行,优势更大
		// 统计 有多少a
		stream = strings.stream();
		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==5);
		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("赵六", 16));
		
		Stream<Student> stream3 = students.stream();
		flag = stream3.anyMatch(u->u.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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
函数接口是指只有一个抽象方法的接口。它们可以被用作lambda达式的目标类型,使得我们能够以更简洁的方定义和使用匿名函数Lambda达式是一种匿名函数,它可以作为参数传递给方法或存储在变量中。它提供了一种更简洁、更灵活的方来编写代码。在Java 8之前,我们使用匿名内部类来实现类似的功能。但是,使用Lambda达式可以更直观地达代码的意图,使代码更易读和易于维护。 Lambda达式可以在很多场景中使用,其中包括事件处理和迭代列。在事件处理方面,Lambda达式可以用来替代传统的匿名内部类,使代码更简洁。例如,使用Lambda达式可以更好地处理Swing API中的事件监听代码。 在迭代列方面,Lambda达式可以用来替代传统的for循环,使代码更简洁和可读性更高。例如,使用Lambda达式可以更方便地对列进行迭代,可以使用forEach方法来实现。 总的来说,函数接口Lambda达式是Java 8中引入的功能,它们可以使代码更简洁、更灵活,并提供了更好的方法来处理事件和迭代列。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Java Lambda达式函数接口实例分析](https://download.csdn.net/download/weixin_38688145/12746209)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Lambda达式函数接口详解](https://blog.csdn.net/weixin_43552143/article/details/122364188)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值