软件设计之Java入门视频(22)
视频教程来自B站尚硅谷:
尚硅谷Java入门视频教程,宋红康java基础视频
相关文件资料(百度网盘)
提取密码:8op3
idea 下载可以关注 软件管家 公众号
学习内容:
该视频共分为1-717部分
本次内容涉及 660-717(后续Java9、10、11新特性就不一一赘述)
在写代码时,总是需要来回切换界面来看代码要求,这里推荐Snipaste,可以把截图以窗口形式放在屏幕上
记录内容:
- 静态代理
- 动态代理
- Lambda表达式
- 函数式接口
- 方法引用
- Stream API
1、静态代理
interface ClothFactory{
void produceCloth();
}
//代理类
class ProxyClothFactory implements ClothFactory{
private ClothFactory factory;//用被代理对象进行实例化
public ProxyClothFactory(ClothFactory factory) {
this.factory = factory;
}
@Override
public void produceCloth() {
System.out.println("代理工厂做准备工作");
factory.produceCloth();
System.out.println("代理工厂做后续工作");
}
}
//被代理类
class NikeClothFactory implements ClothFactory{
@Override
public void produceCloth() {
System.out.println("Nike工厂生产运动服");
}
}
public class StaticProxyTest {
public static void main(String[] args) {
//创建被代理类对象
NikeClothFactory ncf = new NikeClothFactory();
//创建代理类对象
ProxyClothFactory pcf = new ProxyClothFactory(ncf);
pcf.produceCloth();
//代理工厂做准备工作
//Nike工厂生产运动服
//代理工厂做后续工作
}
}
2、动态代理
interface Human{
String getBelief();
void eat(String food);
}
//被代理类
class SuperMan implements Human{
@Override
public String getBelief() {
return "I believe";
}
@Override
public void eat(String food) {
System.out.println("我喜欢吃" + food);
}
}
/*
* 想要实现动态代理,需要解决的问题
* 问题1:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象
* 问题2:当通过代理类的对象调用方法时,如何动态的去调用被代理类中的同名方法*/
class ProxyFactory{
//调用此方法,返回一个代理类的对象,解决问题1
public static Object getProxyInstance(Object obj){//obj:被代理类的对象
MyInvocationHandler handler = new MyInvocationHandler();
handler.bind(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),handler);
}
}
class MyInvocationHandler implements InvocationHandler{
private Object obj;//需要使用被代理类对象进行幅值
public void bind(Object obj){
this.obj = obj;
}
//通过代理类的对象,调用方法a时,会自动调用如下方法:invoke()
//将被代理类要执行的方法a的功能声明在invoke()中
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
//obj:被代理类对象
Object returnValue = method.invoke(obj, args);
return returnValue;
}
}
public class ProxyTest {
public static void main(String[] args) {
SuperMan superMan = new SuperMan();
//proxyInstance代理类的对象
Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
proxyInstance.eat("四川麻辣");//我喜欢吃四川麻辣
}
}
3、Lambda表达式
public class LambdaTest {
//语法格式一:无参,无返回值
@Test
public void test(){
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("输出");
}
};
r1.run();
System.out.println("***********");
Runnable r2 = () -> {System.out.println("输出2");};
r2.run();
}
@Test
//语法格式二:Lambda 需要一个参数,但是没有返回值。
public void test1(){
Consumer<String> con = new Consumer<String>(){
@Override
public void accept(String s){
System.out.println(s);
}
};
con.accept("你好");
System.out.println("********");
Consumer<String> con1 = (String s) -> {System.out.println(s);};
}
@Test
//语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
public void test3(){
Consumer<String> con = new Consumer<String>(){
@Override
public void accept(String s){
System.out.println(s);
}
};
con.accept("你好");
System.out.println("********");
Consumer<String> con1 = (s) -> {System.out.println(s);};
}
@Test
//语法格式四:Lambda 若只需要一个参数时,参数的小括号可以省略
public void test4(){
Consumer<String> con = new Consumer<String>(){
@Override
public void accept(String s){
System.out.println(s);
}
};
con.accept("你好");
System.out.println("********");
Consumer<String> con1 = s -> {System.out.println(s);};
}
@Test
//语法格式五:Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值
public void test5(){
Comparator<Integer> com1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
}
};
System.out.println("**********");
Comparator<Integer> com2 = (o1,o2) -> {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
};
System.out.println(com2.compare(12,6));
}
@Test
//语法格式六:当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略
public void test6(){
Comparator<Integer> com1 = (o1,o2) -> o1.compareTo(o2);;
System.out.println(com1.compare(12,6));
}
}
4、函数式接口
5、方法引用
使用情景
:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用
方法引用本身上就是Lamda表达式
,即也是函数式接口的实例
具体分为三种情况
:
1) 对象 :: 非静态方法
2)类::静态方法
3)类::非静态方法
public class LambdaTest {
//情况一: 对象::实例方法
//Consumer中的void accept(T t)
//PrintStream中的void println(T t)
@Test
public void test(){
Consumer<String> con1 = str -> System.out.println(str);
con1.accept("北京");
System.out.println("**********");
PrintStream ps = System.out;
Consumer<String> con2 = ps::println;
con2.accept("beijing");
}
//
@Test
//情况二: 类::静态方法
//Comparator 中的int compare(T t1, T t2)
//Integer 中的int compare(T t1, T t2)
public void test1(){
Comparator<Integer> com1 = (t1,t2) -> Integer.compare(t1,t2);
System.out.println(com1.compare(12,13));
Comparator<Integer> com2 = Integer ::compare;
System.out.println(com2.compare(12,13));
}
@Test
//情况三: 类::实例方法
//Comparator中的int compare(T t1,T t2)
//String 中的int t1.compareTo(t2)
public void test3(){
Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);
System.out.println(com1.compare("abc","def"));
System.out.println("*********");
Comparator<String> com2 = String ::compareTo;
System.out.println(com2.compare("abc","def"));
}
}
6、Stream API
1、
Stream
关注的是对数据的运算
,与CPU
打交道
2、集合
关注的是数据的存储
,与内存
打交道
3、注意点
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
创建Stream
public class StreamAPITest {
//创建Stream方式一:通过集合
@Test
public void test1(){
List<Employee> employees = EmployeeData.getEmployees();
//default Stream<E> stream():返回一个顺序流
Stream<Employee> stream = employees.stream();
//default Stream<E> parallelStream():返回一个并行流
Stream<Employee> employeeStream = employees.parallelStream();
}
//创建Stream方式二:通过数组
@Test
public void test2(){
int[] arr = new int[]{1,2,3};
// 调用Arrays类的static <T> Stream<T> stream(T[] array): 返回一个流
IntStream stream = Arrays.stream(arr);
Employee e1 = new Employee(1001,"Tom");
Employee e2 = new Employee(1002,"Jerry");
Employee[] arr1 = new Employee[]{e1,e2};
Stream<Employee> stream1 = Arrays.stream(arr1);
}
//创建 Stream方式三:通过Stream的of()
@Test
public void test3(){
Stream<Integer> stream = Stream.of(1,2,3);
}
}
中间操作:筛选
public class StreamAPITest {
//创建Stream方式一:通过集合
@Test
public void test1() {
List<Employee> list = EmployeeData.getEmployees();
//filter(Predicate p)——接收Lambda,从流中排除某些元素
Stream<Employee>stream = list.stream();
stream.filter(e -> e.getSalary() > 7000).forEach(System.out ::println);
System.out.println();
//limit(long maxSize) 截断流,使其元素不超过给定数量
list.stream().limit(3).forEach(System.out ::println);
System.out.println();
//skip(long n)
//跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流与 limit(n) 互补
list.stream().skip(3).forEach(System.out ::println);
//distinct() 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
list.add(new Employee(1010,"刘强东",40,8000));
list.add(new Employee(1010,"刘强东",40,8000));
list.add(new Employee(1010,"刘强东",40,8000));
list.stream().distinct().forEach(System.out ::println);
}
中间操作:映射
@Test
public void test2() {
// map(Function f)接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
List<String> list = Arrays.asList("aa","bb");
list.stream().map(str -> str.toUpperCase()).forEach(System.out ::println);
Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest::fromStringToStream);
streamStream.forEach(s ->{
s.forEach(System.out ::println);
});
//flatMap(Function f)接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
Stream<Character> characterStream = list.stream().flatMap(StreamAPITest::fromStringToStream);
characterStream.forEach(System.out::println);
}
//将字符串中多个字符构成的集合转换为对应的Stream的实例
public static Stream<Character> fromStringToStream(String str){
ArrayList<Character> list = new ArrayList<>();
for (Character c : str.toCharArray()){
list.add(c);
}
return list.stream();
}
中间操作:排序
public class StreamAPITest {
//排序
@Test
public void test2() {
//sorted()——自然排序
List<Integer> list = Arrays.asList(12, 43, 11, 22, 8, 16);
list.stream().sorted().forEach(System.out::println);
//抛异常,原因:Employee没有实现Comparable接口
// List<Employee> employees = EmployeeData.getEmployees();
// employees.stream().sorted().forEach(System.out::println);
//sorted(Comparator com)——定制排序
List<Employee> employees = EmployeeData.getEmployees();
employees.stream().sorted((e1,e2) -> {
return Integer.compare(e1.getAge(),e2.getAge());
}).forEach(System.out::println);
}
}
终止操作:匹配与查找
public class StreamAPITest {
//匹配与查找
@Test
public void test2() {
List<Employee> employees = EmployeeData.getEmployees();
// allMatch(Predicate p) 检查是否匹配所有元素
boolean allMatch = employees.stream().allMatch(e ->e.getAge() > 18);
System.out.println(allMatch);
// anyMatch(Predicate p) 检查是否至少匹配一个元素
boolean anyMatch = employees.stream().anyMatch(e ->e.getAge() > 18);
System.out.println(anyMatch);
// noneMatch(Predicate p) 检查是否没有匹配所有元素
boolean noneMatch = employees.stream().noneMatch(e ->e.getAge() > 100);
System.out.println(noneMatch);
// findFirst() 返回第一个元素
Optional<Employee> employee = employees.stream().findFirst();
System.out.println(employee);
// forEach(Consumer c) 内部迭代
employees.stream().forEach(System.out::println);
//使用集合的遍历操作
employees.forEach(System.out::println);
}
}
终止操作:归约
//归约
@Test
public void test2() {
// reduce(T identity, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 T
//计算1-10自然数和
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer sum = list.stream().reduce(0, Integer::sum);
System.out.println(sum);
// reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 Optional<T>
List<Employee> employees = EmployeeData.getEmployees();
Stream<Double> salaryStream = employees.stream().map(Employee::getSalary);
Optional<Double> sumMoney = salaryStream.reduce(Double::sum);
System.out.println(sumMoney);
}
终止操作:收集
//收集
@Test
public void test2() {
// collect(Collector c)将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
List<Employee> employees = EmployeeData.getEmployees();
List<Employee> employeeList = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
employeeList.forEach(System.out::println);
Set<Employee> employeeSet = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
employeeSet.forEach(System.out::println);
}