动态代理
代理设计模式的原理
使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
静态代理与动态代理
- 静态代理:代理类和目标对象的类在编译期间确定,不利于程序扩展,且每个代理类只能为一个接口服务。
- 动态代理:在程序运行时根据需要动态创建目标类的代理对象,更加灵活和统一。
动态代理的优点
动态代理相比静态代理,将抽象角色中声明的所有方法转移到调用处理器的一个集中方法中处理,可以更灵活和统一地处理众多方法。
演示静态代理(Java代码)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| interface ClothFactory { void produceCloth(); }
class ProxyCloth implements ClothFactory { private ClothFactory clothFactory;
public ProxyCloth(ClothFactory clothFactory) { this.clothFactory = clothFactory; }
@Override public void produceCloth() { System.out.println("代理工厂做一些准备工作..."); clothFactory.produceCloth(); System.out.println("代理工厂做一些收尾工作..."); } }
class NikeClothFactory implements ClothFactory { @Override public void produceCloth() { System.out.println("nike工厂正在生产一批衣服....."); } }
public class StaticProxy { public static void main(String[] args) { ClothFactory nikeClothFactory = new NikeClothFactory(); ClothFactory proxyCloth = new ProxyCloth(nikeClothFactory); proxyCloth.produceCloth(); } }
|
演示动态代理(Java代码)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;
interface Human { String getBelief(); void eat(String food); }
class SuperMan implements Human { @Override public String getBelief() { return "I am superMan!"; }
@Override public void eat(String food) { System.out.println("我喜欢吃" + food); } }
class ProxyFactory { public static Object getProxyInstance(Object obj) { MyInvocationHandler myInvocationHandler = new MyInvocationHandler(obj); return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), myInvocationHandler); } }
class MyInvocationHandler implements InvocationHandler { private Object obj;
public MyInvocationHandler(Object obj) { this.obj = obj; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object returnValue = method.invoke(obj, args); return returnValue; } }
public class ProxyTest { public static void main(String[] args) { SuperMan superMan = new SuperMan(); Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan); System.out.println(proxyInstance.getBelief()); proxyInstance.eat("草莓仙草冻"); } }
|
动态代理与AOP
动态代理是实现AOP(面向切面编程)的核心技术之一,通过动态代理可以在不修改原始代码的情况下,为对象添加额外的功能。
Java 8新特性
Java 8新特性概述
- 速度更快:性能提升。
- 代码更少:增加了新的语法,如Lambda表达式。
- 强大的Stream API:便于数据处理。
- 便于并行:支持并行操作。
- 最大化减少空指针异常:引入Optional类。
- Nashorn引擎:允许在JVM上运行JS应用。
Lambda表达式
什么是Lambda表达式
Lambda是一个匿名函数,可以将代码像数据一样传递,使Java的表达能力更强。
Lambda表达式的使用
- 格式:
(o1, o2) -> Integer.compare(o1, o2);
->左边:Lambda形参列表(接口中的抽象方法的形参列表)。
->右边:Lambda体(重写的抽象方法的方法体)。
Lambda表达式的使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| @Test public void test1() { Runnable runnable = new Runnable() { @Override public void run() { System.out.println("我爱北京天安门"); } }; runnable.run(); System.out.println("---------------------------");
Runnable r2 = () -> { System.out.println("我爱北京天安门."); }; r2.run(); }
@Test public void test2() { Consumer<String> con = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; con.accept("谎言和誓言的区别是什么?"); System.out.println("-------------------------"); Consumer<String> con2 = (String s) -> { System.out.println(s); }; con2.accept("一个是听的人信了,一个是说的人信了"); }
@Test public void test3() { Consumer<String> con1 = (String s) -> { System.out.println(s); }; con1.accept("一个是听的人信了,一个是说的人信了"); System.out.println("----------------"); Consumer<String> con2 = (s) -> { System.out.println(s); }; con2.accept("一个是听的人信了,一个是说的人信了"); }
@Test public void test4() { Consumer<String> con2 = s -> { System.out.println(s); }; con2.accept("一个是听的人信了,一个是说的人信了"); }
@Test public void test5() { Comparator<Integer> com = 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(com.compare(12, 21)); 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 public void test6() { Comparator<Integer> com = (o1, o2) -> o1.compareTo(o2); System.out.println(com.compare(12, 21)); }
|
函数式接口
什么是函数式接口
只包含一个抽象方法的接口,就是函数式接口。可以在接口上使用@FunctionalInterface注解来检查它是否是一个函数式接口。
Java内置四大核心函数式接口
- 消费型接口:
Consumer<T>,void accept(T t)
- 供给型接口:
Supplier<T>,T get()
- 函数型接口:
Function<T,R>,R apply(T t)
- 断定型接口:
Predicate<T>,boolean test(T t)
使用案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| public class CentralFunctionalInterfaces { @Test public void test1() { happyTime(500.0, new Consumer<Double>() { @Override public void accept(Double aDouble) { System.out.println("在天守阁消费" + aDouble); } }); System.out.println("========================"); happyTime(400.0, money -> System.out.println("在望舒客栈消费" + money)); }
public void happyTime(Double money, Consumer<Double> con) { con.accept(money); }
@Test public void test2() { List<String> list = Arrays.asList("北京", "南京", "东京", "天津", "西京"); List<String> filterString = filterString(list, new Predicate<String>() { @Override public boolean test(String s) { return s.contains("京"); } }); System.out.println(filterString); System.out.println("===================="); List<String> list1 = filterString(list, s -> s.contains("京")); System.out.println(list1); }
public List<String> filterString(List<String> list, Predicate<String> pre) { ArrayList<String> filterList = new ArrayList<>(); for (String s : list) { if (pre.test(s)) filterList.add(s); } return filterList; } }
|
方法引用与构造器引用
方法引用基本介绍
当要传递给Lambda体的操作已经有实现的方法时,可以使用方法引用。方法引用是Lambda表达式的一种语法糖。
方法引用的使用
- 格式:
类(或对象)::方法名
- 分为三种情况:
- 对象::实例方法名
- 类::静态方法名
- 类::实例方法名
方法引用的使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| @Test public void test1() { Consumer<String> con = s -> System.out.println(s); con.accept("北京"); System.out.println("********************"); PrintStream ps = System.out; Consumer<String> con2 = ps::println; con.accept("上海"); }
@Test public void test3() { Comparator<Integer> com1 = (t1, t2) -> Integer.compare(t1, t2); System.out.println(com1.compare(12, 21)); System.out.println("-----------分割线------------"); Comparator<Integer> com2 = Integer::compare; System.out.println(com2.compare(12, 1)); }
@Test public void test5() { Comparator<String> com1 = (s1, s2) -> s1.compareTo(s2); System.out.println(com1.compare("abc", "abd")); System.out.println("-----------分割线------------"); Comparator<String> com2 = String::compareTo; System.out.println(com2.compare("c", "a")); }
|
构造器引用
构造器引用与方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Test public void test1() { Supplier<Employee> supplier1 = () -> new Employee(); System.out.println(supplier1.get()); System.out.println("---------------------"); Supplier<Employee> supplier2 = Employee::new; System.out.println(supplier2.get()); }
@Test public void test4() { Function<Integer, String[]> function = length -> new String[length]; String[] arr1 = function.apply(5); System.out.println(Arrays.toString(arr1)); System.out.println("=========================="); Function<Integer, String[]> fun2 = String[]::new; System.out.println(Arrays.toString(fun2.apply(8))); }
|
强大的Stream API
什么是Stream
Stream是Java 8中处理集合的关键抽象概念,用于操作数据源(集合、数组等)所生成的元素序列。
Stream操作的三个步骤
- 创建Stream:通过集合、数组等方式获取一个流。
- 中间操作:对数据源的数据进行处理,多个中间操作可以连接起来形成流水线。
- 终止操作:执行中间操作链,并产生结果。
创建Stream数据源
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| @Test public void test1() { List<Employee> employees = EmployeeData.getEmployees(); Stream<Employee> stream = employees.stream(); Stream<Employee> parallelStream = employees.parallelStream(); }
@Test public void test2() { int[] arr = new int[]{10, 2, 5, 6, 78}; IntStream intStream = Arrays.stream(arr); Employee[] employees = new Employee[]{new Employee(1001, "Tom"), new Employee(1002, "Jerry")}; Stream<Employee> stream = Arrays.stream(employees); }
@Test public void test3() { Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6); }
@Test public void test4() { Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println); Stream.generate(Math::random).limit(5).forEach(System.out::println); }
|
中间操作
筛选与切片
filter(Predicate p):从流中排除某些元素。
limit(long maxSize):截断流,使其元素不超过给定数量。
skip(long n):跳过前n个元素。
distinct():去除重复元素。
映射
map(Function f):将流中的每个元素映射成一个新的元素。
flatMap(Function f):将流中的每个值都换成另一个流,然后把所有流连接成一个流。
排序
sorted():按自然顺序排序。
sorted(Comparator comp):按比较器顺序排序。
Stream的终止操作
匹配与查找
allMatch(Predicate p):检查是否匹配所有元素。
anyMatch(Predicate p):检查是否至少匹配一个元素。
noneMatch(Predicate p):检查是否没有匹配所有元素。
findFirst():返回第一个元素。
findAny():返回任意一个元素。
count():返回流中元素总数。
max(Comparator c):返回流中最大值。
min(Comparator c):返回流中最小值。
forEach(Consumer c):内部迭代。
归约
reduce(T iden, BinaryOperator b):将流中元素反复结合起来,得到一个值。
reduce(BinaryOperator b):将流中元素反复结合起来,得到一个值。
收集
collect(Collector c):将流转换为其他形式,如集合。
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| @Test public void test1() { List<Employee> employees = EmployeeData.getEmployees(); boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 18); System.out.println(allMatch);
boolean anyMatch = employees.stream().anyMatch(e -> e.getSalary() > 10000); System.out.println(anyMatch);
boolean noneMatch = employees.stream().noneMatch(employee -> employee.getName().startsWith("雷")); System.out.println(noneMatch);
Optional<Employee> first = employees.stream().findFirst(); System.out.println(first);
Optional<Employee> any = employees.parallelStream().findAny(); System.out.println(any);
long count = employees.stream().filter(employee -> employee.getSalary() > 3000).count(); System.out.println(count);
Stream<Double> salaryStream = employees.stream().map(Employee::getSalary); Optional<Double> maxSalary = salaryStream.max(Double::compare); System.out.println(maxSalary);
Optional<Employee> employee = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())); System.out.println(employee);
employees.stream().forEach(System.out::println); }
@Test public void test2() { 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);
List<Employee> employees = EmployeeData.getEmployees(); Optional<Double> totalSalary = employees.stream().map(Employee::getSalary).reduce(Double::sum); System.out.println(totalSalary); }
@Test public void test3() { List<Employee> employeeList = EmployeeData.getEmployees().stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList()); employeeList.forEach(System.out::println);
Set<Employee> employeeSet = EmployeeData.getEmployees().stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet()); employeeSet.forEach(System.out::println); }
|
Optional类
Optional类介绍
Optional类是一个容器类,代表一个值存在或不存在,可以避免空指针异常。
常用方法
Optional.of(T t):创建一个Optional实例,t必须非空。
Optional.empty():创建一个空的Optional实例。
Optional.ofNullable(T t):t可以为null。
isPresent():判断是否包含值。
orElse(T t):如果调用对象包含值,返回该值,否则返回t。
orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回s获取的值。
map(Function f):如果有值对其处理,并返回处理后的Optional。
flatMap(Function mapper):与map类似,要求返回值必须是Optional。
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class OptionalTest { @Test public void test1() { Girl girl = new Girl(); Optional<Girl> optionalGirl = Optional.of(girl); }
@Test public void test2() { Girl girl = new Girl(); Optional<Girl> optionalGirl = Optional.ofNullable(girl); System.out.println(optionalGirl); Girl girl1 = optionalGirl.orElse(new Girl("赵丽颖")); System.out.println(girl1); }
public String getGirlName2(Boy boy) { Optional<Boy> boyOptional = Optional.ofNullable(boy); Boy boy1 = boyOptional.orElse(new Boy(new Girl("迪丽热巴"))); Girl girl = boy1.getGirl(); Optional<Girl> girlOptional = Optional.ofNullable(girl); Girl girl1 = girlOptional.orElse(new Girl("古力娜扎")); return girl1.getName(); }
@Test public void test5() { Boy boy = new Boy(new Girl("ikura")); String girlName = getGirlName2(boy); System.out.println(girlName); } }
|