接口的定义方式
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.打印整个队伍的姓名信息。