Java——函数式接口,Lambda表达式,方法引用和构造器引用,Stream,Optional

1.函数式接口,可以自定义函数式接口
(1)消费型接口
它的抽象方法有一个特征:有参无返回值
Consumer 抽象方法:void accept(T t)
消费型接口都以“Consumer”结尾;xxConsumer前面的xx代表形参类型,如:DoubleConsumer void accept(double value):接受一个double值
(2)供给型接口
它的抽象方法有一个特征:无参有返回值
Supplier` 抽象方法:T get()
供给型接口以“Supplier”结尾;xxSupplier代表返回xx类型的结果,如:DoubleSupplier double getAsDouble():返回一个double值
(3)判断型接口
它的抽象方法有一个特征:有参有返回值,返回值类型是boolean
Predicate 抽象方法:boolean test(T t)
判断型接口抽象方法的返回值类型只有boolean;xxPredicate说明形参是xx类型
(4)功能型接口
它的抽象方法有一个特征:有参有返回值
Function 抽象方法 R apply(T t)
以Unary开头的表示是一元的,泛型的类型只有一个,形参和返回值类型都是同一种类型;
xxFunction说明形参的类型是xx类型;
toXXFunction说明返回值类型是xx类型;
xxToyyFunction说明形参的类型是xx类型,返回值类型是yy类型
xxUnary开头的,表示一元的,形参类型和返回值类型都是xx
Bi开头表示二元的
BinaryOperator,Bi开头表示两个形参,Operator结尾,表示形参和返回值类型一样
toXXBi开头的,表示返回类型是xx,形参是两个
xxBinaryOperator,表示两个形参,形参和返回值类型一样为xx类型

  1. Lambda表达式

Lambda表达式是为了给函数式接口(SAM接口)的变量和形参赋值的表达式,替代了使用匿名内部类的对象给函数式接口的变量或形参赋值的形式
Lambda表达式也要实现接口,重写接口的抽象方法,隐含的创建了对象,Lambda表达式是为SAM接口的变量和形参赋值的,那么实现接口这部分语法可以省略;SAM接口的抽象方法只有一个,因此方法签名可以省略部分,如:修饰符,返回值类型,方法名可以省略,但其中的形参列表不能省略

	Lambda表达式语法格式:
		(形参列表)->{Lambda体}

说明:(形参列表)是SAM接口的抽象方法的形参列表;{Lambda体}是实现SAM接口的抽象方法的方法体,

(1)如果{Lambda体}只有一句语句,可以省略{}以及{}中的语句的结束符“;”
(2)如果(形参列表)中形参的类型是已知的,或者可以推断,那么数据类型可以省略
(3)如果(形参列表)只有一个形参,并且数据类型也已经省略了,那么这个()可以省略
(4)如果{Lambda体}只有一句语句,并且是一个return语句,可以省略{}以及{}中的语句的结束符“;”,还有return
(5)如果没有形参,()不可以省略

3 . 方法引用和构造器引用
方法引用和构造器引用是用来简化Lambda表达式,当Lambda表达式满足一些条件时,才能使用方法引用和构造器引用
条件:
(1)当Lambda体的实现是通过调用一个现有的方法来完成功能时
(2)要求函数式接口的抽象方法的返回值类型与该方法返回值类型要对应
(3)要求函数式接口的抽象方法的形参列表与该方法的形参列表对应;或者要求函数式接口的抽象方法的形参列表的第一个形参是作为调用方法的对象,剩余的形参正好是给这个方法的实参列表
方法引用的语法格式:
(1)对象::实例方法名
(2)类名::静态方法名
(3)类名::实例方法名

	@Test
	public void test1(){
		List list=Arrays.asList(1,2,3);
		//default void forEach(Consumer action)
		list.forEach(num->System.out.println(num));
			//简化为
			list.forEach(System.out::println);
		//这里的Lambda表达式是通过调用一个现有方法来完成的,即out对象的println()方法
		//Consumer      public void accept(T t)
		//PrintStream类的out对象 public void println(Object x)
	}

	@Test
	public void test2(){
		String[] arr={"h","q","w"};
		// public static void sort(T[] a,Comparator c)
		//Comparator的抽象方法:int compare(String s1,String s2)
		Arrays.sort(arr,(s1,s2)->s1.compareToIgnoreCase(s2));
		//Comparator接口   int compare(String s1,String s2)
		//String类        int compareToIgnoreCase(String str)  此处s1正好是调用compareToIgnoreCase的对象,s2是给它的参数
			Arrays.sort(arr,String::compareToIgnoreCase);
	}

条件:
(1) 当Lambda体的实现是通过创建一个对象来实现的
(2)要求函数式接口的抽象方法返回值类型与该对象的类型一致
(3)要求函数式接口的抽象方法的形参列表与该对象创建时的构造器的形参列表对应
构造器引用语法格式:
(1)类名::new
(2)数组类型::new

	@Test
	public void test(){
		//Supplier接口的抽象方法 T get()
		//Supplier s=()-> new String();
		Supplier s=String::new; 
	}

	@Test
	public void test(){
		//方法public  R[] cr(Function fun,int length)
		//String[] arr=cr((Integer i)->new String[i],10);
		String[] arr=cr(String::new,10);
	}
  1. Stream API
    用于处理数据,处理集合等容器中的数据,处理操作有:查询,筛选,删除,过滤,统计,映射等
    Stream的操作
    (1)创建Stream
    (2)加工处理
    (3)终结操作:收集结果
    一旦终结就不能再加工了,如果要加工需要重新创建Stream
    Stream的特点:
    (1)Stream本身不负责存储数据,只负责对数据进行处理,加工
    (2)Stream是不可变的,一旦修改就会产生新的Stream对象,Stream不会修改数据源的数据
    (3)Stream的操作是一个延迟操作,所有的操作都必须延迟到终结操作时,一起处理
    Stream接口的实现类:IntStream,DoubleStream,LongStream
    创建Stream集合
    (1)通过集合创建
    集合对象.stream

     @Test
     public void test(){
     	List list=Arrays.asList(1,2,3);
     	Stream stream=list.stream();
     }
    

(2)通过数组工具类Arrays
Arrays.stream(数组对象)

	@Test
	public void test(){
		int[] arr={1,2,3};
		IntStream stream=Arrays.stream(arr);
	}
	@Test
	public void test1(){
		String[] arr={"h","q"};
		Stream stream=Arrays.stream(arr);
	}

(3)通过Stream接口的静态方法of,产生一个有限流

	Stream stream=Stream.of(1,2,3);
	stream.forEach(System.out::println);

	Stream stream=Stream.generate(Math::random);
	stream.forEach(System.out::println);

(4)通过Stream接口的静态方法

generate方法,产生一个无限流
Stream iterate(T seed,UnaryOperator f)产生一个无限流

加工操作
(1)filter(Predicate p) :过滤
(2)distinct():去重
(3)limit(long maxSize):取有限的几个
(4)skip(long n):跳过n个
(5)peek(Consumer action):接受Lambda表达式,对流中的每个数据执行Lambda体操作
(6)sorted():排序,按照自然排序
sorted(Comparator com):排序,按照定制排序
(7)map(Function f):接受Lambda表达式,对流中的每个数据,执行Lambda体操作,返回新的数据构成新的流
(8)flatMap(Function f)
map(Function mapper) map操作流中把T对象变成R对象,由R对象构成新的流
flatMap(Function> mapper) flatMap把流中的数据T对象压扁变成一个Stream,再把一个个Stream合成一个大的Stream

	@Test
	public void test(){
		Stream stream=Stream.of(1,2,3);
		stream=stream.filter(t->t%2==0);
		stream.forEach(System.out::println);
		//简化
		Stream.of(1,2,3)
			.filter(t->t%2==0)  //过滤
			.forEach(System.out::println);
		Stream.of(1,2,3,2,5,3,4,5,7,2,3,4)
			.skip(3);        //跳过3个
			.distinct()         //去重
			.limit(3)           //取前面的3个
			.forEach(System.out::println);
	}
		@Test
	public void test1(){
		String[] arr={"h","q"};
		Stream stream=Arrays.stream(arr);
		stream.map(t->t.toUpperCase())
			.forEach(System.out::println);
	}

终结操作
(1)void forEach(Consumer):遍历流中的数据
(2)long count()
(3)boolean allMatch(Predicate p):检查是否全部满足条件
boolean anyMatch(Predicate p):是否有一个满足xx条件
boolean noneMatch(Predicate p):检查是否全部都不满足xx条件
(4)Optional findFirst():返回第一个
Optional findAny():返回任意一个
(5)Optional max(Comparator c)
Optional min(Comparator c)
(6)T reduce(T iden,BinaryOperator b)

Optional类为了解决空指针异常
Optional是一个装一个对象的容器,这个对象可能是空,也可能是非空
创建Optional对象的方法:
(1)Optional.of(xx):只能装非空对象
(2)Optional.ofNullable():可以装空对象
(3)Optional empty():直接返回一个空箱子对象
取出Optional容器中的对象的方法:
(1)get():必须配合of(xx)使用,因为这里面的对象不能是null
(2)orElse(T other):如果Optional容器中的对象是空的,用other代替
(3)orElseGet(Supplier other)如果Optional容器中的对象是空的,用other这个供给型接口提供的对象代替
(4)orElseThrow(SupplierexceptionSupplier)

	@Test
	public void test(){
		String str=null;
		Optional opt=Optional.ofNullable(str);
		//String string=opt.orElse("d");
		//String string=opt.orElseGet(String::new);
	    //String string=opt.orElseThrow(()->new RuntimeException("没有值")); 
		System.out.println(string);
	}

你可能感兴趣的:(Java——函数式接口,Lambda表达式,方法引用和构造器引用,Stream,Optional)