复习
1.反射-获取字段
1.获取Class对象
2.
getFields(): 获取公共字段
getDeclaredFields():获取所有的字段
Field是一个类,用于表示字段这类事物,该类的一个对象代表的是Class对象表示的类型中的一个字段
类中提供了: void set(对象,属性值) Object get(对象)
3.getFields(字段名) 获取指定的公共字段
2.反射-获取方法
1.获取Class对象
2.getMethods(): 获取公共方法,包括继承
3.getDeclaredMethods():获取所有方法,不包括继承
Method是一个类,用于表示方法这类事物,该类的一个对象代表的是Class对象表示的类型中的一个方法
类中提供了: Object invoke(对象,实参)
4.getMethod(形参的Class类型) : 获取指定的公共方法
3.新特性-接口
1.jdk8: 接口中新增 默认方法 和 静态方法
2.jdk9: 接口中新增 私有默认方法 和 私有静态方法
jdk8:
1.静态方法,只能通过接口名.静态方法去调用,子类并不继承该方法
2.默认方法: 实现类可以重写也可以不重写
实现类想要调用接口中的指定的默认方法: 接口名.super.默认方法()
4.新特性-Lambda表达式
Lambda表达式:本质其实就一个值,是一个特殊的匿名的子类对象
前提: 是针对接口,并且这个接口有且只有一个抽象方法
格式:
(参数列表) -> {方法体语句};
说明: (参数列表) : 接口中抽象方法的参数列表
-> : 就是一个符号,将表达式内容分成左右两边部分
{方法体语句} : 接口中抽象方法的实现代码
种类:
无参数、无返回值: () -> {...};
无参数、有返回值: () -> {return ...};
有参数、无返回值: (参数列表名) -> {...};
有参数、有返回值: (参数列表名) -> {return...};
省略原则:
左边: 参数类型只有一个, 小括号和参数类型 都可以省略
参数类型有多个, 参数类型可以省略,但是小括号不可以省略
右边: 体语句有且只有一行 , return和大括号都可以省略
课程
一. 函数式接口
(一) 概述
1、定义:如果在接口中,只有一个抽象方法,那么这个接口就是函数式接口,比如:jdk中熟悉的函数式接口 :Runnable
2、格式说明:
使用注解来检查当前接口是否是一个函数式接口
@FunctionalInterface
如果不是函数式接口,则编译报错
3、理解:
(1) 函数:想表达的是一个方法的内容,由于方法不在任何类中,所以称为函数
(2) 函数式接口:其实想表达的就是一个抽象函数的声明
4、作用:
使用函数式接口表达函数的声明;使用函数式接口的实现类对象表达函数的实现
5、使用原因:
Java中不支持将函数作为一个数据,也就不能将这个函数进行各种传递,也就不能作为对象的成员变量存在
只能在方法外加一层接口的声明,将来可以传递方法所在接口的实现类对象,来间接的传递方法实现内容
举例 : 客户要求定义出一个方法功能, 对两个整数进行任意操作
- 两数求和
- 两数求差
- 两数乘积 * 2
- … 无数需求, 都需要在同一个方法中完成
public int useTwoInt(int x, int y, 对于x和y两数的操作思想,这个思想可以是一个抽象方法){
}
(二) 常用内置函数式接口
1、说明:
Java8中提供了一些常用的函数式接口,在使用类似功能的时候,不需要额外定义接口,直接使用jdk中提供的即可
package com.ujiuye;
/*
* 函数式接口:
* 也是一个接口,是一种特殊形式的接口。
* 接口中的成员:
* 抽象方法 : 1个,必须有
* 默认/静态方法: 个数不限制
* 可以同一个注解来验证是否是函数接口 : @FunctionalInterface ,定义接口的上边。
* */
public class Demo1 {
public static void main(String[] args) {
String s = test(new Inter<String>() {
@Override
public String method(String s) {
return s.toUpperCase();
}
},"abc");
System.out.println(s);
System.out.println("----------------------------");
String ss = test( s1-> s1.toUpperCase(), "abc");
System.out.println(ss);
ss = test( s1-> s1, "abc");
System.out.println(ss);
}
//根据给定的字符串,将其转为大写形式返回
public static String test (Inter<String> in, String str){ //in = new 实现类对象 str = "abc";
String s = in.method(str);
return s;
}
}
//自定义函数式接口
@FunctionalInterface
interface Inter<T>{
public T method(T t);
}
2、罗列:
Consumer:消费型接口
void accept(T t): 需要传进进来参数,进行消费,没有返回值。【有进无出】
3、 Supplier:供给型接口
T get(): 不需要传递参数,返回创建一个数据的接口 【无进有出】
4、 Function<T, R>:函数型接口
R apply(T t): 需要传递一个参数,把传递进来的参数进行一些操作,然后再返回一个参数【有进有出】
5、 Predicate:断言型接口
boolean test(T t): 需要参数,返回一个boolean类型的值【有进有出,出来的结果一定是boolean类型】
(三) 消费型接口
1、Consumer : 消费型接口
2、抽象方法:void accept(T t) 消费使用掉任意的一个数据
3、作用:
定义一个方法,这个方法需要传递进来数据,还需要传递进来处理这个数据的方式,并且还不需要返回值类型,就可以使用Consumer接口来当做数据处理方式的传递。
有了Consumer接口接口以后,不仅仅可以传递数据,还可以传递消费处理数据的方式。
(四) 供给型接口
1、Supplier:供给型接口
2、抽象方法:T get() 提供返回任意类型数据的规则
3、作用:
当一个方法需要去生产一些数据,并且生产数据的方式不确定,就可以在方法的形参列表位置传递一个 Supplier接口,将来让调用该方法的调用者把如何生产数据的方式传递进来。有了供给型接口之后,不仅仅可以传递生产数据的数量等信息,也可以传递生产数据的方式。
(五) 函数型接口
1、Function<T, R>: 函数型接口
2、抽象方法:R apply(T t) 方法提供把一个数据类型转换为另一个数据类型的规则
3、作用:
如果需要定义一个函数,接收一个数据,将数据进行处理,完成之后,还能返回一个结果,就可以使用函数型接口,以前我们只能传递处理好之后的数据,或者将原始数据传入方法,现在可以传入处理方式
4、提供其他功能:
Function andThen(Function f):在调用者处理方式之后,再进行参数的处理方式调用
(六) 断言型接口
1、Predicate: 断言型接口
2、抽象方法:boolean test(T t) 判断给定的数据是否符合某个条件
3、作用:
如果需要定义一个函数,接收一个数据,判断数据是否合法,返回一个boolean结果,就可以使用断言型接口,以前我们只能传递过滤好的数据,而现在既可以传递原始数据,也可以传递过滤的条件
4、其他功能:
Predicate and(Predicate pre):在调用者条件判断之后,再由参数条件判断,返回两个条件都满足的判断对象
Predicate or(Predicate pre):返回两个条件任意一个满足的判断对象
Predicate negate():取判断结果的反向结果
package com.ujiuye;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/*
* jdk8:
* 核心函数式接口(4个)
* 消费型: 有参数,无返回值
* 供给型: 无参数,有返回值
* 断言型: 有参数,返回值boolean
* 函数型: 有参数,有返回值
* */
public class Demo2 {
public static void main(String[] args) {
//消费型---根据给定的字符串输出打印字符串的长度
Consumer<String> con = new Consumer<String>(){
@Override
public void accept(String s) {
System.out.println(s.length());
}
};
Consumer<String> con = s -> System.out.println(s.length());
con.accept("12345");
System.out.println("----------------------------------------------");
//供给型 -- 计算两个常量5的和
Supplier<Integer> sup = new Supplier<Integer>(){
@Override
public Integer get() {
return 5+5;
}
};
Supplier<Integer> sup = () -> 5+5;
System.out.println( sup.get());
System.out.println("----------------------------------------------");
//断言型---(用来做判断的),根据给定的字符串,判断首字符是否以a开头
Predicate<String> pre = new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("a");
}
};
Predicate<String> pre = s -> s.startsWith("a");
System.out.println(pre.test("abcdef"));;
System.out.println("----------------------------------------------");
//函数型--根据给定的字符串,返回其长度
Function<String , Integer> fun = new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return s.length();
}
};
Function<String,Integer> fun = s -> s.length();
System.out.println(fun.apply("qwert"));
}
}
package com.ujiuye;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
public class Demo3 {
public static void main(String[] args) {
Predicate<String> p1 = s -> s.length() > 5;
Predicate<String> p2 = p1.and(s -> s.startsWith("a")); // & 计算
Predicate<String> p2 = p1.or(s -> s.startsWith("c")); // | 计算
Predicate<String> p2 = p1.negate(); // ! 计算
System.out.println(p2.test("abcdef"));
Function<Integer,Integer> fun1 = x -> x+x;
//计算fun1的值,将结果赋值给y,然后在计算y+y
Function<Integer, Integer> fun2 = fun1.andThen(y -> y + y);
System.out.println(fun2.apply(5));
Consumer<String> con1 = s -> System.out.println(s);
Consumer<String> con2 = con1.andThen(s -> System.out.println(s.length()));
con2.accept("abcd");
}
}
二. 方法引用
1、写一个函数式接口时,方法的实现(lambda体),已经被某个其他的对象实现了,就不需要在Lambda体中,再次实现一遍,而可以直接使用那个已经定义好的方法。
2、格式:
函数式接口 名称 = 对象名 :: 方法名称;
函数式接口 名称 = 类名 :: 静态方法名;
3、作用:
把已经实现的方法,作为一个数据,作为实现类对象,赋值给某个函数式接口的引用
可以把这个引用当做方法的返回值,也可以作为方法的实际参数进行传递
4、本质:
可以把任意一个方法,作为函数式接口的一个实现类对象
package com.ujiuye;
import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.*;
/*
* 方法引用:
* 简单理解:Lambda表达式的简写。
* Lambda体部分,即箭头右边部分,功能已经被对象实现了,直接使用方法引用形式即可
* 格式:
* 对象名 :: 方法名
* 类名 :: 静态方法名
* */
public class Demo4 {
public static void main(String[] args) {
PrintStream ps = System.out;
Consumer<String> con = s -> ps.println(s);
Consumer<String> con1 = ps :: println;
Consumer<String> con2 = System.out :: println;
con.accept("abc");
con1.accept("abc");
//accept : 参数类型是:String 返回值类型是:void
//println : 参数类型是:String 返回值类型是:void
System.out.println("-------------------------------");
Comparator<Integer> com = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
//Comparator-compare :参数类型 Integer 返回值类型 int
//引用方法:compare : 参数类型 int 返回值类型 int
Comparator<Integer> com1 = (x,y) -> Integer.compare(x,y);
Comparator<Integer> com2 = Integer::compare;
//com2.compare(5,6);
//特点: 接口中抽象方法的参数列表与返回值类型 和 引用的方法的参数列表与返回值类型 一致。
//类名 :: 实例方法名
//Comparator-compare :参数类型 Integer 返回值类型 int
Comparator<Integer> com3 = Integer::compareTo;
BiPredicate<String,String> bip = (s1,s2) -> s1.startsWith(s2);
BiPredicate<String,String> bip1 = String :: startsWith;
BiPredicate<String,String> bip2 = String :: equals;
//特点: 接口中抽象方法的第一个参数 是引用方法的调用者 ,第二个参数(无参)是引用方法的参数
System.out.println("-----------------------------------------------------------------");
//构造方法引用
//格式: 类名 :: new
Supplier<String> sup = () -> new String();
Supplier<String> sup1 = String :: new;
Supplier<Person> sup2 = new Supplier<Person>() {
@Override
public Person get() {
return new Person();
}
};
Supplier<Person> sup3 = () -> new Person();
Supplier<Person> sup4 = Person::new;
Function<String, Person> sup5 = Person::new;
BiFunction<String , Integer,Person> sup6 = Person::new;
System.out.println(sup6.apply("zhangsan",20));
//特点: 接口中抽象方法的参数列表 要与 引用的构造方法的参数列表一致。
//数组引用
//格式 : 元素类型[] :: new
Function<Integer, String[]> fun = new Function<Integer, String[]>() {
@Override
public String[] apply(Integer integer) {
return new String[integer];
}
};
Function<Integer,String[]> fun1 = String[] :: new;
Function<Integer,String[]> fun2 = (num) -> new String[num];
}
}
三. StreamingAPI
(一)概述
Stream是jdk8增加的一个接口,该接口提供了一些对容器数据进行操作的规则,有了这些规则就可以在不遍历容器的情况下完成对相关数据的操作处理。
Stream可以理解为像生产流水线,操作只能往前走不能回退,经过一道工序操作的数据就会发生变化,上一道工序的对象就消失不可再次使用.
注意: Stream虽然可以操作数据但是本身不能够存储任何数据
(二) Stream类型数据的获取
1、Collection的获取:
调用stream()方法即可,返回Stream接口类型的实现类对象
因为stream是default默认方法, 因此可以被单列集合所有类型继承使用: List,Set
2、Map的获取:不能直接获取Stream类型
(1) keySet().stream()
(2) values().stream()
values() : 获取到Map集合中的所有value值, 放置在Collection容器中
(3) entrySet().stream()
3、数组的获取
Stream中的静态方法static Stream of(T… values),获取到数组上的流资源使用
package com.ujiuye;
import java.util.*;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/*
* StreamAPI:
* 简单理解: 可以对数据源中的数据进行想要的计算,(如:过滤、去重、转换...),得到一个想要的结果集。
* 注意:数据源数据并没有变化
* 数据源数据: 集合或数组
* 对数据源数据进行计算时,是一种流水线模式(中间操作)。
* 采用的是惰性求值,意味着只有看到终止命令,才进行中间操作的计算
* Stream只做计算,不做存储
* 步骤:
* 1.获取Stream对象
* 2.中间操作
* 3.终止
* */
public class Demo5 {
public static void main(String[] args) {
//获取Stream对象
//Collection: stream()
//Map是双列集合,需要将双列转为单列后, 通过stream()
//Stream类中的静态方法 of()
List<String> list = new ArrayList<>();
Collections.addAll(list, "aaa","444","333","6666","11","2");
HashMap<String,String> map = new HashMap<>();
map.put("1","zhangsan");
map.put("2","lisi");
map.put("3","wangwu");
map.put("4","zhaoliu");
Stream<String> stream = list.stream();
Stream<String> stream2 = map.keySet().stream();
Stream<String> stream1 = Stream.of("11", "22", "33", "44", "5");
//数据工具类中提供的静态 stream()方法
Stream<Integer> stream3 = Arrays.stream(new Integer[]{1,2,3,4});
}
}
(三) Stream中的常用方法
- Stream filter(Predicate p):
按照指定的条件对stream中数据进行过滤【满足保留】 - Stream limit(int num):
只获取Stream中前num个元素 - Stream skip(int num):
跳过前num个数据获取之后的数据 - Stream map(Function f):
映射功能【把Stream中的数据映射为另一种数据】 - Stream concat(Stream s1,Stream s2):
静态方法,拼接两个stream流为一个stream流 - toArray():
把stream流中的数据收集到数组中 - collect(Collector c):
把stream流中的数据收集到指定的集合中
Collector :参数的类型是一个接口,获取可以通过工具类Collectors
常用:
(1) 获取List集合:Collectors.toList()
(2) 获取Set集合:Collectors.toSet() - forEach(Consumer c):
用来使用stream流中的数据的 - int count():
返回stream流中元素的个数
方法总结
延迟方法:返回值类型还是Stream类型的方法就是延迟方法
终结方法:返回值不是Stream类型是其他的数据类型是终结方法
package com.ujiuye;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Demo6 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Collections.addAll(list, "aaa","444","333","6666","11","2");
//之前方式:
for(int i =0 ; i< list.size(); i++){
if(list.get(i).length() >= 3){
System.out.println(list.get(i));
}
}
//streamAPI方法:
Stream<String> stream = list.stream();
stream = stream.filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.length() >= 3;
}
});
stream.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
Stream<String> stream = list.stream();
stream = stream.filter( s -> s.length() >= 3);
stream.forEach( s -> System.out.println(s));
list.stream()
.filter( s -> s.length() >= 3) //过滤, 将数据源中的数据长度大于等于3以上的过滤
.forEach( System.out :: println);
System.out.println("-----------------------------------------");
list.stream()
.distinct() //去重,去除重复元素
.forEach( System.out::println);
System.out.println("-----------------------------------------");
list.stream()
.filter( s->s.length() >= 3)
.distinct()
.forEach( System.out::println);
System.out.println("-----------------------------------------");
list.stream()
.limit(3) //从第一个到指定个数
.forEach( System.out::println);
System.out.println("-----------------------------------------");
list.stream()
.skip(3) //跳过指定个数
.forEach(System.out::println);
System.out.println("-----------------------------------------");
Stream<String> s1 = Stream.of("11", "22", "33");
Stream<String> s2 = Stream.of("66", "99", "55");
//将两个Stream对象合并成一个Stream
Stream<String> s3 = Stream.concat(s1, s2);
s3.forEach(System.out::println);
System.out.println("-----------------------------------------");
list.stream()
//.map( (s) -> s.toUpperCase() )
.map( String :: toUpperCase) //转换、映射
.forEach(System.out::println);
System.out.println("-----------------------------------------");
//终止方法:
long count = list.stream().count(); //统计个数
System.out.println(count);
//将数据收集都数组中
Object[] objects = list.stream().toArray();
System.out.println(Arrays.toString(objects));
//收集方法
//将结果收集到List集合中
List<String> collect1 = list.stream().collect(Collectors.toList());
System.out.println(collect1);
//将结果收集到Set集合中
Set<String> collect2 = list.stream().collect(Collectors.toSet());
System.out.println(collect2);
//将结果收集到Collection中
ArrayList<String> collect = list.stream().collect(Collectors.toCollection(() -> new ArrayList<>()));
HashSet<String> collect = list.stream().collect(Collectors.toCollection(() -> new HashSet<>()));
Map<String, Integer> collect = list.stream().collect(Collectors.toMap((s) -> s.toUpperCase(), (s) -> s.length()));
System.out.println(collect);
}
}
练习
package com.ujiuye;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class Demo7 {
public static void main(String[] args) {
ArrayList<Person> list = new ArrayList<>();
Collections.addAll(list, new Person("小红1",17),
new Person("小红2",19),
new Person("小红3",27),
new Person("小红4",35),
new Person("小红5",22));
//1.过滤年龄大于25岁以上的,输出
//2.获取前三个person对象 ,收集到list集合中
//3.获取后两个person对象 ,手机到set集合中
list.stream()
.filter( p -> p.age > 25)
.forEach(System.out::println);
System.out.println("--------------------------------------");
List<Person> collect = list.stream()
.limit(3)
.collect(Collectors.toList());
System.out.println(collect);
System.out.println("--------------------------------------");
Set<Person> collect1 = list.stream()
.skip(3)
.collect(Collectors.toSet());
System.out.println(collect1);
}
}
package com.ujiuye;
public class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name) {
this.name = name;
}
public Person(){
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}