经过一段时间,java的学习,明显感到就是一个用的过程,与嵌入式开发明显的不同。嵌入式一些虽然也有库,但大部分的开发过程都是根据实际的芯片手册来写一些底层的驱动,其次才是构建在OS基础上的开发。如果说嵌入式开发也是盖楼的话,那么还要有一个造砖的过程,而java开发主要是往框架里填砖的过程。
常用函数式接口:有且只有一个抽象方法的接口
java中函数式编程的体现就是Lambda.只有确保接口中有且只有一个抽象方法,java中的Lambda才能顺利推导。
注:“语法糖”是指使用更加方便,但是原理不变的代码语法。例如在遍历集合时使用的for-each语法,其实底层的实现原理仍然是迭代器,这便是“语法糖”。从应用层面来讲,Java中的Lambda可以被当做是匿名内部类的“语法糖”,但是二者在原理上是不同的。
格式:
修饰符 interface 接口名称 {
public abstract 返回值类型 方法名称(可选参数信息);
// 其他非抽象方法内容
}
@FunctionalInterface 函数式接口注解
作用:与 @Override 注解一样,检测接口是否是一个函数式接口
是,编译成功
否,编译失败,(接口中没有抽象方法,抽象方法的个数多于1个)
函数式接口的使用:一般作为方法的参数和返回值使用。
Lambda特点:延时加载。
使用Lambda表达式作为参数传递,仅仅是把参数传递到showLog方法中,只有满足条件,才会调用接口中的方法。如果条件不满足,不会调用接口中的方法
常用的函数式接口:java.util.function包下
Supplier接口:生产数据
java.util.function.Supplier<T>接口仅包含一个无参的方法: T get() 。用来获取一个泛型参数指定类型的对象数据。
Supplier<T>接口被称为生产型接口,指定接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据。
Consumer接口:消费数据
java.util.function.Consumer<T>接口中包含抽象方法 void accept(T t) ,意为消费一个指定泛型的数据。
泛型执行什么类型,就可以使用accept方法消费什么类型的数据
andThen方法:作用:需要两个Consumer接口,可以把两个ConSumer接口组合到一起,在对数据进行消费
java.util.function.Predicate<T> 接口
Predicate接口中包含一个抽象方法:boolean test(T t):用业指定数据类型数据进行判断的方法
结果 :符合条件,返回true
不符合条件,返回false
默认方法:and,表示 并且关系,也可以用于连接两个判断条件。
方法内部的两个判断条件,也是使用&&运算符连接起来的。
默认方法:or表示或者关系,也可以用于连接两个判断条件
默认方法:negate也表示取反的意思。
java.util.function.Function<T,R> 接口用来根据一个类型的数据得到另一个类型的数据
最主要的抽象方法为: R apply(T t) ,根据类型T的参数获取类型R的结果
Function 接口中有一个默认的 andThen 方法,用来进行组合操作。
Stream流:
使用Stream流方式,遍历集合,对集合中的数据进行过滤,关注的是做什么,而不是怎么做。
使用格式:
list.stream().filter
使用的三个基本步骤:
获取一个数据源(source)可以是集合跟数组 → 数据转换(集合跟数组转换成流)→执行操作获取想要的结果,每次转换原有Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换),允许对其操作可以像链条一样排列,变成一个管道。
获取Stream流两种方式:
java.util.stream.Stream<T> 是Java 8新加入的最常用的流接口。(这并不是一个函数式接口。)
常用的获取方法:
所有的 Collection 集合都可以通过 stream 默认方法获取流;
default Stream<E> stream()
Stream 接口的静态方法 of 可以获取数组对应的流
static <T> Stream<T> of (T....values)
常用方法:
分为两种:
延迟方法:返回值类型仍然是 Stream 接口自身类型的方法,因此支持链式调用。(除了终结方法外,其余方法均为延迟方法。)
终结方法:返回值类型不再是 Stream 接口自身类型的方法,因此不再支持类似 StringBuilder 那样的链式调用。本小节中,终结方法包括 count 和 forEach 方法。
逐一处理:forEach:
void forEach(Consumer<? super T> action);//该方法接收一个 Consumer 接口函数,会将每一个流元素交给该函数进行处理。
用来遍历流中的数据,遍历之后就不能继续调用Stream流中的其他方法
过滤:filter:
filter 方法将一个流转换成另一个子集流
Stream<T> filter(Predicate<? super T> predicate);
Stream特点:属于管道流,只能被消费(使用)一次。
映射:map
将流中的元素映射到另一个流中,可以使用 map 方法.
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
该接口需要一个 Function 函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的流。
统计个数:count
用于统计Stream流中元素的个数,是一个终结方法,返回值是一个long类型的整数,不能再调用Stream流中的其他方法
取用前几个:limit
Stream<T> limit(long maxSize);//参数是一个long类型,如果集合当前长度大于参数则进行截取;否则不进行操作。
limit方法是一个延迟方法,只是对流中的元素进行截取,返回的是一个新的流,所以可以继续调用Stream流中的其他方法。
跳过前几个:skip
Stream<T> skip(long n);//如果流的当前长度大于n,则跳过前n个;否则将会得到一个长度为0的空流
组合:concat,静态方法,可通过接口名直接调用
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)//把a,b两个流合并成一个流
方法的引用:
使用Lambda表达式的时候,我们实际上传递进去的代码就是一种解决方案:拿什么参数做什么操作。如何实现简化呢????
@FunctionalInterface
public interface Printable {
void print(String str);
}
public class Demo01PrintSimple {
private static void printString(Printable data)
{
data.print("Hello, World!");
}
public static void main(String[] args)
{
printString(s ‐> System.out.println(s));//换成printString(System.out::println);就是方法引用
}
}
方法引用符::
如果Lambda要表达的函数方案已经存在于某个方法的实现中,那么则可以通过双冒号来引用该方法作为Lambda的替代者。
引用方法:
通过对象名引用成员方法:前提是对象,成员方法都已经存在
public class MethodRefObject {
public void printUpperCase(String str) {
System.out.println(str.toUpperCase());
}
}
@FunctionalInterface
public interface Printable {
void print(String str);
}
public class Demo04MethodRef {
private static void printString(Printable lambda) {
lambda.print("Hello");
}
public static void main(String[] args) {
MethodRefObject obj = new MethodRefObject();
printString(obj::printUpperCase);
}
}
通过类名称引用静态方法:使用前提:类已经存在,静态方法也已存在
java.lang.Math 类中已经存在了静态方法 abs
首先是函数式接口
@FunctionalInterface
public interface Calcable {
int calc(int num);
}
使用Lambda表达式
public class Demo05Lambda {
private static void method(int num, Calcable lambda) {
System.out.println(lambda.calc(num));
}
public static void main(String[] args) {
method(‐10, n ‐> Math.abs(n));//method(‐10, Math::abs);简化Lambda
}
}
通过super引用成员方法:引用父类的成员方法
前提:super是已经存在的,父类的成员方法也是已经存在的
使用this来引用本类的成员方法:
引用的方法就是当前类中的成员方法,那么可以使用“this::成员方法”的格式
类的构造器引用:
构造器的名称与类名完全一样,并不固定。所以构造器引用使用 类名称::new 的格式表示。
数组的构造器引用:也就是使用引用来创建数组
前提是已知创建的是什么类型的数组,数组的长度也是已知的,就可以使用方法引用来创建数组。
java web基础准备:
Junit单元测试:白盒测试中的一种,即需要写代码的,关注程序具体的执行流程
Junit如何使用:
1、定义一个测试类(测试用例),建议,1、类名:被测试的类名Test 2、包名:xxx.xxx.xx.test
2、定义测试方法,可以独立运行,建议:1、方法名:tes测试方法名 2、返回值 void 3、参数列表 空表
3、给方法加@Test
4、添加Junit依赖环境,导入Test包 org.junit.Test
判断结果,一般使用Assert.assertEquals(期望的结果,运算的结果);
Junit两个注解:
@Before: 一般用于资源申请,所有的测试方法在执行之前都会先执行该方法
@After:释放资源,在所有的测试方法执行完后,都会自动执行该方法
反射:框架设计的灵魂
框架:半成品软件。简化编码。
什么是反射:可以理解就是一个代码框,这个框可以放不同的对象,调用方法时只需要调用这个框就可以,更神奇的是可通过xml预调用。具体使用的例子见扩展:
好处:
1、在程序运行过程中可以操作这些对象
2、可以解耦,增加程序的可扩展性
获取反射的class(字节码)对象方式:
1、class.forName("全类名,也就是全路径名“):将字节码文件加载进内存,返回class对象,多用于配置文件,将类名配置在文件中,读取文件加载类。
如 Class mm=Class.forName("com.lean.ssm.chapter1.Cat");
2、类名.class:通过类名的属性class获取,多用于参数的传递,适合在编译前就知道操作的 Class
如:Class ss = String.class;
3、对象.getClass():方法,在object类中定义的,多用于对象的获取字节码的方式。
String str = new String("Hello");
Class cs = str.getClass();
注:
同一个字节码文件,只会加载一次进内存。不论通过哪种方式获取。
使用class对象的功能:
1、获取成员变量,属性、方法,构造器
Field[] getField()://获取所有public修饰的成员变量,无法获取到私有属性
如:
Class clz = Cat.class;
Field[] fields = clz.getFields();
for (Field field : fields) {
System.out.println(field.getName());
}
Field[] getField(String name)://获取指定名称public修饰的成员变量
Field[] getDeclaredFields()://获取所有的成员变量,不考虑修饰符
Class clz = Cat.class;
Field[] fields = clz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName());
}
Field[] getDeclaredFields(String name)://获取所有指定名称 的成员变量,
注:
Field:成员变量
1、设置值:
void set(Object obj,Object value)
2、获取值
get(Object obj)
3、忽略访问权限修饰符的安全检查
setAccessible(true):暴力反射
2、获取构造方法
Constructor<T> getConstructors(class<?>...parameterTypes)
注:
Constructor:构造方法
创建对象的
T newInstance(Object... initargs)
如果使用空参数构造方法创建对象,操作可以简化:Class对象的NewInstance方法
创建类对象的两种方法:
通过 Class 对象的 newInstance() 方法
Class clz = Cat.class;
Apple apple = (Cat)clz.newInstance();
通过 Constructor 对象的 newInstance() 方法
Class clz = Cat.class;
Constructor constructor = clz.getConstructor();
Cat black = (Cat)constructor.newInstance();
通过 Constructor 对象创建类对象可以选择特定构造方法,而通过 Class 对象则只能使用默认的无参数构造方法。下面的代码就调用了一个有参数的构造方法进行了类对象的初始化。
Class clz = Cat.class;
Constructor constructor = clz.getConstructor(String.class, String.class);
Cat apple = (Cat)constructor.newInstance("红色", “red”);
3、获取成员方法
Methrod[] getMethods();//获取所有public修饰的方法
Methrod[] getMethods(String name,class<?>... parameterTypes);//获取指定名称的方法
Method:方法对象
执行方法:
Object invoke(Object obj,Object...args)
获取方法名称:
Object getName()
4、获取类名
类名.getName().也是getName()方法。
注解:
概念:说明程序的。是给编译器看的。
JDK预定义注解
1.@Override:检测被该注解标注的方法是否继承自父类(接口)的。
2.@Deprecated:将该注解标注的内容,已过时
3.@SuppressWarnings:压制警告,需要传参,一般传递 all
自定义注解:
格式:
元注解
public @interface 注解名称()
本质:
就是一个接口 ,继承自 java.lang.annotation
注解属性:接口里可以定义的抽象方法
要求:1、属性的返回值类型只有下列取值,基本数据类型、字符串、枚举,以上类型的数组
2、定义了属性,在使用时需要给属性赋值,如果定义属性使用default默认初始化时,可以不赋值,若只有一个属性需要赋值,并且属性名称是value,则赋值时value可以省力,直接赋什么值就可以了,数组赋值时,值使用{}包裹。
元注解:用于描述注解的注解
@Target:描述注解能够作用的位置
@Retention:描述注解被保留的阶段
@Documented:描述注解是否被抽取到api文档中
@Inherited:描述注解是否被子类继承
在程序中使用(解析)注解:获取注解中定义的属性值
1、获取注解定义的位置的对象(class,method,field)
2、获取指定的注解 使用的方法是 getAnnotation(Class).
3、调用注解中的抽象方法获取配置的属性值
扩展:反射的使用例子
/**
* Copyright (C), 2015-2021, XXX有限公司
* FileName: Cat
* Author: guang
* Date: 2021/2/2 17:55
* Description:
* History:
* <author> <time> <version> <desc>
* 作者姓名 修改时间 版本号 描述
*/
package com.lean.ssm.chapter1;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* 〈一句话功能简述〉<br>
* 〈〉反射的例子
*
* @author guang
* @create 2021/2/2
* @since 1.0.0
*/
public class Cat {
private String color;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public static void main (String[] args) throws Exception{
Cat black=new Cat();
black.setColor("黑色的猫");
System.err.println("什么颜色的猫? "+ black.getColor());
//反射实现
Class mm=Class.forName("com.lean.ssm.chapter1.Cat");
Method setColorMethrod=mm.getMethod("setColor", String.class);
Constructor catConstruct=mm.getConstructor();
Object catob=catConstruct.newInstance();
setColorMethrod.invoke(catob,"红色的猫");
Method getColorMethrod=mm.getMethod("getColor");
System.err.println("什么颜色的猫? " + getColorMethrod.invoke(catob));
}
}