Java jdk8新特性(接口定义方式、Lambda、Stream流)

接口的定义方式

jdk7接口的特点:

1、接口中的方法都是抽象方法,接口中的属性都是静态常呈。
2、实现类实现接口,必须要实现接口中所有的抽象方法
3、实现类可以实现多个接口
4、接口不能实例化
5、接口不能写构造方法。

在java8以后,接口中可以添加使用default或者static修饰的方法,在这里我们只讨论default方法,default修饰方法只能在接口中使用,在接口中被default标记的方法为普通方法,可以直接写方法体

static方法特点:
1、用static修饰的方法可以有方法体
2、实现该接口的类可以不重写用static修饰的方法
3、可以使用接口名直接调用被static修饰的方法。

default方法特点:
1.用default修饰的方法可以有方法体,实现该接口的类可以不重写用default修饰的方法,实现类会继承接口中的default方法
2.如果一个类同时实现接口A和B,接口A和8中有相同的default方法,这时,该类必须重写接口中的default方法注意:为什么要重写呢?是因为,类在继承接口中的default方法时,不知道应该继承哪一个接口中的default方法。
3.如果子类继承父类,父类中有b方法,该子类同时实现的接口中也有b方法(被default修饰),那么子类会继承父类的b方法而不是继承接口中的b方法。如果子类重写了b方法,就调用自己的b方法。

Lambda表达方式

1)函数式编程思想概述
在数学中,函数就是有输入量,输出量的一套计算方案,也就是"“拿什么东西做什么事情”。相对而言,面向对象过分强调"必须通过对象的形式来做事情",而函数式思想则尽量忽略面向对象的复杂语法――强调做什么,而不是以什么形式做。
做什么,而不是怎么做
我们真的希望创建一个匿名内部类对象吗?不。我们只是为了做这件事情而不得不创建一个对象。我们真正希望做的事情是:将run方法体内的代码传递给Thread类知晓。
传递一段代码—―这才是我们真正的目的。而创建对象只是受限于面向对象语法而不得不采取的一种手段方式。那,有没有更加简单的办法?如果我们将关注点从"“怎么做"回归到做什么”"的本质上,就会发现只要能够更好地达到目的,过程与形式其实并不重要。

public static void main(String[] args) {
			new Thread(new Runnable() {
				public void run() {
					System.out.print("123");
				}
			}).start();
			
			///Lambda改造:去除复杂的形式,直接执行方式中的内容。提高代码简洁的
			//():表示接口的参数
			//->:操作符,去做什么事情
			new Thread(()-> System.out.print("456")).start();
		}

总结:
1.函数式编程思想概念
函数式思想则尽量忽略面向对象的复杂语法――强调做什么,而不是以什么形式做工
2.lambda表达式写法
技巧:
只需要按照匿名内部类的形式写出代码,然后保留抽象方法的()和{}.在()和{}之间添加一个->
一条执行语句 用() {}可省,多条语句{}不可省
3) Lambda的格式标准格式:
Lambda省去面向对象的条条框框,格式由3个部分组成:
。一些参数
。一个箭头
。一段代码
Lambda表达式的标准格式为:

(参数类型参数名称)->{代码语句}

格式说明:
·小括号内的语法与传统方法参数列表一致:无参数则留空;多个参数则用逗号分隔。
·->是新引入的语法格式,代表指向动作。本质是方法参数的传递;注意:中间不能空格,要连写。
·大括号内的语法与传统方法体要求基本一致。
4)参数和返回值:
语法格式:

(参数列表)->{...return xxx;}

在后面的案例中,使用3种书写方式做对比:
1.匿名内部类对象的方式
2.lambda表达式的标准方式
3.lambda表达式的简化方式
案例:
List集合存储多个Person对象,完成对List集合的排序,按照年龄升序排序
代码

5) Lambda表达式的省略格式
(1)数据类型可以省略:(Person p1,Person p2):省略格式(p1,p2)
(2)()中只有一个参数()可以省略:(Person p):省略格式§最简化的省略格式: p
(3)->:永远不能省略
(4)有中如果只有一条语句:
那么{},return,分号都可以省略但是要么全部省略.要么全部保留
6) lambda表达式的前提
(1)必须要有接口(函数式接口)
要求接口中只能有一个(必须要坡覆盖重写的)抽象方法,可以有默认方法,可以有静态方法

(2)必须要有接口作为方法的参数
注意:lambda表达式是对匿名内部类对象的简化书写格式
@Override:检测是否是对父类方法的覆盖重写
@Functionallnterface:检测是否是函数式接口
(3)凡是使用了@Functionallnterface都可以使用lambda表达式

函数式接口

1))概述
函数式接口在ava中是指:有且仅到一个抽象方法的接口。
函数式接口,即适用于函数式编程场景的接口。而Java中的函数式编程体现就是Lambda,所以函数式接口就是可以适用于Lambda使用的接口。只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导。
2)格式
只要确保接口中有且仅有一个抽象方法即可:

修饰符interface接口名称{
public abstract 返回值类型方法名称(可选参数信息);
//其他非抽象方法内容

3)自定义函数式接口
案例;
自定义函数式接口: MyFunctionalInter.使用3种表达方式书写。

package com.m.demo;
//必须添加注解
@FunctionalInterface
public interface MyFunctionalInter {
	public void fun();//有且只有一个抽象方法
	public static void fun2() {//可静态方法
		System.out.println("123");
	}
	public default void fun3() {//可以有default方法
		System.out.println("456");
	}
	
}

4)常用函数式接口
JDK提供了大量常用的函数式接口以丰富Lambda的典型使用场景,它们主要在java.util.function包中被提供。下面是两个常用的函数式接口及使用示例。
A)消费型接口:Consumer=必须掌握
java.util.function.consumer<T>接口,是消费一个数据,其数据类型由泛型参数决定。

抽象方法:
`public abstract void accept(T t):`消费一个T类型的数拓t什么叫做消费呢?
因为accept方法是抽象的,只要做覆盖重写{},就叫消费了,至于{}中写了哪些代码,我不管

案例;
定义字符串:Hello wor1d
定义方法,使用函数式接口consumer作为参致分别使用:
1、使用内部类对象的方式:输出字符串内容
2、lambda表达式的标准方式:输出宁符长度
3、lambda表达式的简化方式:全部转换成大写

package com.m.demo;

import java.util.function.Consumer;

public class Test2 {

	public static void main(String[] args) {
		String str="HelloWorld";
		//使用内部类对象的方式:输出字符串内容
		fun(str,new Consumer<String>() {

			@Override
			public void accept(String t) {
				System.out.println(t);
				
			}
			
		});
//		lambda表达式的标准方式:输出字符长度
		fun(str,(String t)->{System.out.println(t.length());});
//		lambda表达式的简化方式:全部转换成大写
		fun(str,t->System.out.println(t.toUpperCase()));

	}
	public static void fun(String str,Consumer <String>consumer) {
		consumer.accept(str);
	}
}


B)判断型接口:Predicate =必须掌握
有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用java.uti7.function.Predicate<T>接口。

抽象方法: 

public abstract boolean test(T t):根据给定的方法参数T类型的t,返回一个boolean类型的结果

案例:
定义字符冲:Helloworld
定义方法,使用函数式接口Predicate
1、判断字符冲长度是否人于5
2、判断字符串是否包含"“H”"

package com.m.demo;

import java.util.function.Predicate;

public class Test3 {

	public static void main(String[] args) {
		String str="HelloWorld";
		boolean flag=fun(str,new Predicate<String>() {

			@Override
			public boolean test(String t) {
				
				return t.length()>5;
			}
			
		});
		System.out.println(flag);
		
		flag=fun(str,t->t.contains("H"));
		System.out.println(flag);
		
		
		
		
	}
	
	public static boolean fun(String str,Predicate <String> pre) {
		//抽象方法
		
		return pre.test(str);
		
	}
}

Stream流 (和IO流不是一个概念)

在Java 8中,得益于Lambda所带来的函数式编程,引入了一个全新的Stream概念,用于解决已有集合类库既有的弊端。
传统集合的多步遍历代码
几乎所有的集合(如Collection接口或Map接口等)都支持直接或间接的遍历操作。而当我们需要对集合中的元素进行操作的时候,除了必需的添加、删除、获取外,最典型的就是集合遍历。
循环遍历的弊端
Java 8的Lambda让我们可以更加专注于做什么(What),而不是怎么做(How),这点此前已经结合内部类进行了对比说明。

  • for循环的语法就是""怎么做”
  • for循环的循环体才是“做什么""

为什么使用循环?因为要进行遍历。但循环是遍历的唯一方式吗?遍历是指每一个元素逐一进行处理,而并不是从第一个到最后一个顺次处理的循环。前者是目的,后者是方式。
案例:找到姓张的且名字为三个字

package com.m.demo;

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

public class Test4 {
public static void main(String[] args) {
	List<String> list=new ArrayList<String>();
	Collections.addAll(list,"张三","李四","王五","张三四","张三五");
	Stream<String> stream = list.stream();
	//使用Stream+lambda表达式操作  Stream需要返回值才能继续操作
	///找到姓张的且名字为三个字
	Stream<String> filter = stream.filter(s->s.startsWith("张"));//Predicate
	Stream<String> filter2 = filter.filter(s->s.length()==3);
	filter2.forEach(s->System.out.println(s));//consumer
	//list.stream().filter(s->s.startsWith("张")&&s.length()==3).forEach(s->System.out.println(s));
}
}

生产流水线:
在这里插入图片描述

获取Stream流对象

1、方法1=掌握

java.uti1.collection<T>接口
默认方法:必须由collection接口的实现类(ArrayList/LinkedList/Hashset/LinkedHashset)对象调用
pub1ic default stream<T> stream():获取co11ection集合对象对应的Stream流对象
//List集合
		List<String> list=new ArrayList<>();
		Stream<String> stream = list.stream();
		
		//set集合
		Set<Integer> set=new HashSet<>();
		Stream<Integer> stream2 = set.stream();
		
		//map集合
		Map<String,Integer> map=new HashMap<>();
		Set<String> keySet = map.keySet();
		keySet.stream();
		Set<Entry<String, Integer>> entrySet = map.entrySet();
		Stream<Entry<String, Integer>> stream3 = entrySet.stream();

2、方法2

java.uti7.stream.Stream<T>接口
静态方法:
public static <T> Stream<T> of(T ... t):把方法的可变多数指定的只体数拓,转换成Stream流对象
参数:
T ... t:可变参数传送数纽,多数列长
		String[] s= {"abc","a","b"};
		Stream<String> s1= Stream.of(s);
		s1.forEach(m->System.out.println(m));

Stream流中的count方法

stream流中的常用方法
抽象方法:因为获取到的都是stream的实现类对象,必然覆盖重写抽象方法,
所以可以直接使用用public abstract long count()统计stream流对象中元素的个数

Stream流中的limit方法和skip方法

stream<T> limit(long n):获取流对象中的前n个元素,
返回新的Stream流对象stream<T> skip(long n):跳过流对象中的前n个元素,
返回新的Stream流对象

Stream流中的静态concat方法

stream流中的静态方法
public static <T> stream<T> concat(Stream<T> a,stream<T> b):
把参数列表中的两个Stream流对象a和b,合并成一个新的Stream流对象

综合案例
现在有两个ArrayList集合存储队伍当中的多个成员姓名,要求使用传统的for循环(或堵强for循环)和stream流依次进行以下若干操作步骤;
1.第一个队伍只要名字为3个字的成员姓名:
2.第一个队伍筛选之后只要前3个人:
3.第二个队伍只要姓张的成员姓名;
4、第二个队伍筛选之后不要前2个人;
5.将两个队伍合并为一个队伍;
6.打印整个队伍的姓名信息。

代码

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值