1、定义:规定集合类或集合接口中存放的数据类型
2、特点:
①实例化集合类时,可以指明具体的泛型类型
②泛型的类型必须是类
③实例化时,如果没有指明泛型类型,则默认是Object类型
④静态方法中不能使用泛型
⑤泛型不同的引用不能相互赋值
⑥父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型:
1)子类不保留父类的泛型,按需实现:没有类型,擦除;具体类型
2)子类保留父类的泛型,泛型子类:全部保留;部分保留
3、泛型方法
定义:在方法中出现了泛型的结构,泛型参数与类泛型参数没有任何关系
泛型方法可以声明为静态
4、DAO:data access object
用于对数据库数据进行增删改查操作等共性操作的最基本对象,然后由继承其的子类(指定了泛型类型)完成各自表数据的操作。
5、泛型在继承方面:
①类A是类B的父类,G<A>
和G<B>
二者不具备子父类关系,两者是并列关系
②类A是类B的父类,A<G>
和B<G>
二者具备子父类关系
6、通配符
表示:?
类A是类B的父类,G<A>
和G<B>
两者是并列关系,二者的共同父类是G<?>
G<?>
是不能向其中添加数据;除了添加null
G<?>
可以获取Object类型的数据
有限制条件的通配符:
G<? extends A>
:可以作为G<A>
和A的子类的G<>的父类;获取数据可以用A类接收
G<? super A>
:可以作为G<A>
和A的父类的G<>的父类;获取数据只能用Object接收;添加数据可以添加A类及A类的子类
7、IO流
File类:代表一个文件或文件目录
File类特点:
①只会涉及到文件的创建、删除、重命名等,并不会读取和写入文件内容
②File通常会作为参数传入I/O流的构造器中
创建文件对象方法:
①public File(String pathname)
:以pathname为路径创建File对象,可以是绝对路径或相对路径
②public File(String parent, String child)
:以parent为父路径,child为子路径创建File对象
③public File(File parent, String child)
:根据一个父File对象和子文件路径创建File对象
File类常用方法:
获取方法:
String getAbsolutePath()
:获取绝对路径
String getPath()
:获取路径
String getName()
:获取名称
String getParent()
:获取上层文件目录路径。若无,返货null
long length()
:获取文件长度(字节数)
long lastModified()
:获取最后一次修改时间(毫秒值)
String[] list()
:获取指定目录下的所有文件或者文件目录的名称数组
File[] listFiles()
:获取指定目录下的所有文件或者文件目录的File数组
重命名方法:
boolean renameTo(File dest)
:把文件重命名为指定的文件路径
该方法成功的条件:调用rename的File对象必须存在,dest对象不能存在
判断方法:
boolean isDerectory()
:判断是否是文件目录
boolean isFile()
:判断是否是文件
boolean exists()
:判断是否存在
boolean canRead()
:判断是否可读
boolean canWrite()
:判断是否可写
boolean isHidden()
:判断是否隐藏
创建文件方法:
boolean createNewFile()
:创建文件。若文件存在,则不创建,返回false;
boolean mkdir()
:创建文件目录。如果上层文件目录不存在,不创建;如果该文件存在,不创建
boolean mkdirs()
:创建文件目录。如果上层文件目录不存在,一并创建
删除文件方法:
boolean delete()
:删除文件或者文件夹。删除这个操作是不走回收站的
流的分类:
按操作数据单位:字节流(8 bit)、字符流(16bit)
按角色:节点流、处理流
节点流:可以从或向一个特定的地方(节点)读写数据。如FileReader.
处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。
流的体系结构:
抽象基类:InputStream
、OutputStream
、Reader
、Writer
节点流(文件流):FileInputStream
、FileOutputStream
、FileReader
、FileWriter
缓冲流:BufferedInputStream
、BufferedOutputStream
、BufferedReader
、
BufferedWriter
输入流:
①文件必须存在
②
@Test
public void demo() {
FileReader fileReader = null;
try {
//实例化File对象,指明操作文件
File file = new File("hello.txt");
//提供具体的流
fileReader = new FileReader(file);
//数据读入
//返回读入一个字符,如果读到文件末尾,返回-1
int data;
while ((data = fileReader.read()) != -1){
System.out.println((char)data);
}
}catch (IOException e){
e.printStackTrace();
}finally {
//流的关闭
try {
if (fileReader != null){
fileReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出流:
①文件可以不存在;若不存在,则新建一个文件写入
②空参构造器的write()函数会直接覆盖原有的信息
缓冲流作用:提升流的读取、写入的速度
原因:内部提供了一个缓冲区
@Test
public void demo() {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//创建读出、写入文件对象
File srcfile = new File("C:\\Users\\82784\\Desktop\\桌面\\01-23.jpg");
File desfile = new File("C:\\Users\\82784\\Desktop\\桌面\\01-24.jpg");
//创建节点流
FileInputStream fis = new FileInputStream(srcfile);
FileOutputStream fos = new FileOutputStream(desfile);
//创建处理流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//进行图片、视频复制
byte[] buffer = new byte[5];
int len;
while ((len = bis.read(buffer)) != -1){
bos.write(buffer,0, len);
}
}catch (IOException e){
e.printStackTrace();
}finally {
//关闭处理流、节点流
//关闭处理流会自动关闭节点流
if (bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bis != null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void demo() {
BufferedReader br = null;
BufferedWriter bw = null;
try {
//创建读出、写入文件对象
File srcfile = new File("C:\\Users\\82784\\Desktop\\桌面\\01-23.jpg");
File desfile = new File("C:\\Users\\82784\\Desktop\\桌面\\01-24.jpg");
//创建节点流
FileReader fr = new FileReader(srcfile);
FileWriter fw = new FileWriter(desfile);
//创建处理流
br = new BufferedReader(fr);
bw = new BufferedWriter(fw);
//进行文本复制
String str;
while ((str = br.readLine()) != null){
bw.write(str);
bw.newLine();
}
}catch (IOException e){
e.printStackTrace();
}finally {
//关闭处理流、节点流
//关闭处理流会自动关闭节点流
if (bw != null){
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (br != null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
转换流:
InputStreamReader
:将一个字节的输入流转化为字符的输入流
OutputStreamWriter
:将一个字符的输出流转化为字节的输出流
作用:提供字节流和字符流之间的转换
标准的输入、输出流
System.in:标准的输入流,默认从键盘输入
System.out:标准的输出流,默认从控制台输出
通过System的setIn(InputStream is)、setOut(PrintStream os)来重新指定输入和输出的流
打印流:
PrintStream
PrintWriter
数据流:
DataInputStream
DataOutputStream
作用:用于读取或写出基本数据类型的变量或字符串
对象流:
ObjectInputStream
ObjectOutputStream
作用:用于读取和存储基本数据类型数或对象的处理流
序列化:用ObjectOutputStream类保存基本数据类型或对象的机制
@Test
public void demo() {
ObjectOutputStream oos = null;
try{
oos = new ObjectOutputStream(new FileOutputStream("test.dat"));
oos.writeObject(new String("ababababa"));
oos.flush();
}catch (IOException e){
e.printStackTrace();
}finally {
if (oos != null){
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
反序列化:用ObjectInputStream类读取基本数据类型或对象的机制
注意:ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量
对象可序列化的要求:
①必须实现Serializable或Externalizable接口之一
②类需要提供一个全局常量:serialVersionUID
③其内部所有属性都是可序列化的(默认情况下,基本数据类型可序列化)
对象序列化机制:允许把内存中Java对象转换为平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制传输到另一个网络节点。当其他程序获得了这种二进制流,就可以恢复成原来的Java对象
RandomAccessFile类:
①直接继承于Object类,实现了DataInput和DataOutput接口
②既可以作为输入流,又可以作为输出流
③作为输出流时,写入到的文件不存在则自动创建;写入到的文件存在,则从头开始写入
④用seek(int pos)函数调整写入文件的位置
构造器:
①public RandomAccessFile(File file, String mode)
②public RandomAccessFile(String name, String mode)
mode类别:r(以只读方式打开) rw(打开以便读取和写入) rwd(打开以便读取和写入,同步文件内容的更新) rws(打开以便读取和写入,同步文件内容和元数据的更新)
Java NIO:
NIO支持面向缓冲区(IO是面向流的)、基于通道的IO操作。
Path、Paths和Files核心API:
Paths类提供静态get()方法获取Path对象
关于java.lang.Class类的理解:
①类的加载过程:程序经过javac.exe命令以后,会生成一个或多个字节码文件,接着使用java.exe命令对某个字节码文件进行解释运行,相当于将某个字节码文件加载到内存中。
②加载到内存中的类,称为运行时类,该类作为Class的一个实例
③获取Class实例方法
//方式一:调用运行时类的属性:.class
Class clazz = Person.class;
//方式二:通过运行时类的对象,调用getClass()
Person person = new Person();
Class clazz = person.getClass();
//方式三:调用Class的静态方法:forName(String classPath)
Class clazz = Class.forName("com.fj.lean01.Person");
//使用类的加载器:ClassLoader
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
Class clazz = classLoader.loadClass("com.fj.lean01.Person");
④加载到内存中的运行时类,会缓存一段时间,在此时间内,我们可以通过不同的方式来获取运行时类
类加载器:
//对于自定义类,使用系统类加载进行加载
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
//调用系统类加载器的getParent():获取扩展类加载器
ClassLoader classLoader1 = classLoader.getParent();
//调用扩展类加载器的getParent():无法获取引导类加载器
//引导类加载器主要负责加载Java核心类库,无法加载自定义类
ClassLoader classLoader2 = classLoader1.getParent();
读取配置文件:
Properties properties = new Properties();
//方式一:文件默认在当前module下
FileInputStream fis = new FileInputStream("jdbc.properties");
properties.load(fis);
//方式二:文件默认在当前module的src下
ClassLoader classLoader = test.class.getClassLoader();
FileInputStream fis = classLoader.getResourceAsStream("jdbc.properties");
properties.load(fis);
创建运行时类的对象
Class<Person> clazz = Person.class;
//newInstance():创建对应的运行时类的对象(调用运行时类的空参构造器)
Person person = clazz.newInstance();
获取运行时类的属性结构
Class clazz = Person.class;
//getFields():获取当前运行时类的及其父类中声明为public的属性
Field[] fields = clazz.getFields();
//getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)
Field[] declaredFields = clazz.getDeclaredFields();
for (Field f : declaredFields){
//权限修饰符
int modifier = f.getModifiers();
System.out.print(Modifier.toString(modifier) + "\t");
//数据类型
Class type = f.getType();
System.out.print(type.getName() + "\t");
//变量名
String name = f.getName();
System.out.println(name);
}
获取运行时类的方法结构
Class clazz = Person.class;
//getMethods():获取当前运行时类的及其父类中声明为public的方法
Method[] methods = clazz.getMethods();
//getDeclaredFields():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m : declaredMethods){
//方法声明的注解
Annotation[] annotations = m.getAnnotations();
for (Annotation annotation : annotations){
System.out.print(annotation);
}
//权限修饰符
int modifier = m.getModifiers();
System.out.print(Modifier.toString(modifier) + "\t");
//返回值类型
System.out.print(m.getReturnType().getName() + "\t");
//方法名
String name = m.getName();
System.out.print(name + "(");
//形参列表
Class[] parameterTypes = m.getParameterTypes();
//有形参列表
if (!(parameterTypes == null || parameterTypes.length == 0)){
for (int i = 0;i < parameterTypes.length;i++){
if (i == parameterTypes.length - 1){
System.out.print(parameterTypes[i].getName() + " args_" + i);
break;
}
System.out.print(parameterTypes[i].getName() + " args_" + i + ",");
}
}
System.out.print(")");
//抛出的异常
Class[] exceptionTypes = m.getExceptionTypes();
//有异常抛出
if (!(exceptionTypes == null || exceptionTypes.length == 0)){
System.out.print(" throws ");
for (int i = 0;i < exceptionTypes.length;i++){
if (i == exceptionTypes.length - 1){
System.out.print(exceptionTypes[i].getName());
}
System.out.print(exceptionTypes[i].getName() + ", ");
}
}
System.out.println();
}
获取运行时类的构造器结构
Class clazz = Person.class;
//getConstructors():获取当前运行时类中声明为public的构造器
Constructor[] constructors = clazz.getConstructors();
//getDeclaredConstructors():获取当前运行时类中声明的所有构造器
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
获取运行时类的父类
Class clazz = Person.class;
//getSuperclass():获取当前运行时类的父类
Class superclass = clazz.getSuperclass();
//getGenericSuperclass():获取当前运行时类的带泛型父类
Type genericSuperclass = clazz.getGenericSuperclass();
//getGenericSuperclass():获取当前运行时类的带泛型父类的泛型
Type genericSuperclass = clazz.getGenericSuperclass();
ParameterizedType paramType = (ParameterizedType)genericSuperclass;
//获取泛型类型
Type[] actualTypeArguments = paramType.getActualTypeArguments();
调用运行时类中指定的结构
Class clazz = Person.class;
//创建运行时类的对象
Person person = (Person) clazz.newInstance();
//获取指定的属性方式一(要求获取的属性是为public的)
Field id = clazz.getField("id");
//获取指定的属性方式二
Field name = clazz.getDeclaredField("name");
//设置当前属性为可访问
name.setAccessible(true);
//设置当前属性的值
id.set(person,1001);
//获取当前属性的值
int personId = (int) id.get(person);
Class clazz = Person.class;
//创建运行时类的对象
Person person = (Person) clazz.newInstance();
//获取指定的方法方式一(要求获取的方法是为public的)
Method id = clazz.getMethod("id");
//获取指定的方法方式二
Method equals = clazz.getDeclaredMethod("equals");
//设置当前属性为可访问
equals.setAccessible(true);
//调用方法invoke(),如果调用的是静态方法,则不需要传入参数或者传入调用类.class
equals.invoke(person);
Class clazz = Person.class;
//获取指定的构造器方式一(要求获取的方法是为public的)
Constructor constructor = clazz.getConstructor();
//获取指定的构造器方式二
Constructor constructor = clazz.getDeclaredConstructor(int.class, String.class);
//设置当前属性为可访问
constructor.setAccessible(true);
//调用方法newInstance()
Person person = (Person) constructor.newInstance(1001, "Tom");
静态代理:
特点:代理类和被代理类在编译期间,就确定下来了
interface ClothFactory{
void produceCloth();
}
//代理类
class ProxyClothFactory implements ClothFactory{
private ClothFactory clothFactory;//用被代理类对象进行实例化
public ProxyClothFactory(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 StaticProxyTest {
public static void main(String[] args) {
//创建被代理类对象
NikeClothFactory nikeClothFactory = new NikeClothFactory();
//创建代理类对象
ProxyClothFactory proxyClothFactory = new ProxyClothFactory(nikeClothFactory);
proxyClothFactory.produceCloth();
}
}
动态代理:
interface Human{
String getBelief();
void eat (String food);
}
//被代理类
class Superman implements Human{
@Override
public String getBelief() {
return "I believe i can fly!";
}
@Override
public void eat(String food) {
System.out.println("我喜欢吃" + food);
}
}
class ProxyFactory{
//返回一个代理类对象
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;
}
//被代理类要执行的功能写在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);
System.out.println(proxyInstance.getBelief());
proxyInstance.eat("abc");
NikeClothFactory nike = new NikeClothFactory();
ClothFactory proxyInstance1 = (ClothFactory) ProxyFactory.getProxyInstance(nike);
proxyInstance1.produceCloth();
}
}
Java8新特性:
Lambda表达式:是一个匿名函数
(o1, o2) -> Integer.compare(o1, o2);
格式:
->:lambda操作符 或 箭头操作符
(o1, o2):lambda形参列表
右侧:lambda体
lambda的使用(6种情况)
//语法格式一:无参,无返回值
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("XXXXXXXX");
}
};
Runnable r2 = () -> {
System.out.println("XXXXXXXX")
};
//语法格式二:有参数,无返回值
Consumer<String> con = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
Consumer<String> con1 = (String s) -> {
System.out.println(s);
};
//语法格式三:数据类型可以省略,可由编译器推断得出,称为“类型推断”
Consumer<String> con1 = (String s) -> {
System.out.println(s);
};
Consumer<String> con1 = (s) -> {
System.out.println(s);
};
//语法格式四:lambda只要一个参数时,参数的小括号可以省略
Consumer<String> con = (s) -> {
System.out.println(s);
};
Consumer<String> con1 = s -> {
System.out.println(s);
};
//语法格式五:lambda需要两个参数以上,多条执行语句,并且可以有返回值
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);
}
};
Comparator<Integer> com1 = (o1, o2) -> {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
};
//语法格式六:当lambda体只有一条执行语句,return和大括号若有,都可以省略
Comparator<Integer> com = (o1, o2) -> {
return o1.compareTo(o2);
};
Comparator<Integer> com1 = (o1, o2) -> o1.compareTo(o2);
lambda表达式的本质:作为函数式接口的实例
曾经用匿名实现类实现的现在都可以用lambda表达式来完成
函数式接口:一个接口中只声明了一个抽象方法的接口
@FunctionalInterface
public interface MyInterface{
void method();
}
Java内置四大核心函数式接口
其他接口
方法引用:
使用情况:当要传递给lambda体的操作,已经有实现的方法了,可以使用方法引用
方法引用本质上就是lambda表达式,,而lambda表达式作为函数是接口的实例。所以方法引用也是函数式接口的实例
格式:类(对象) :: 方法名
具体为三种:
①对象 :: 非静态方法
②类 :: 静态方法
③类 :: 非静态方法
使用要求:接口中的抽象方法的形参列表和返回值与方法引用的方法的形参列表和返回值类型相同
//情况一:对象 :: 非静态方法
//Consumer中的void accept(T t)
//PrintStream中的void println(T t)
Consumer<String> con = str -> System.out.println(str);
PrintStream ps = System.out;
Consumer<String> con1 = ps :: println;
//情况二:类 :: 静态方法
//Comparator中的int compare(T t1, T t2)
//Integer中的int compare(T t1, T t2)
Comparator<Integer> com = (t1, t2) -> Integer.compare(t1, t2);
Comparator<Integer> com1 = Integer :: compare;
//情况三:类 :: 非静态方法
//Comparator中的int compare(T t1, T t2)
//String中的int t1.compareTo(t2)
Comparator<String> com = (s1, s2) -> s1.compareTo(s2);
Comparator<String> com1 = String :: compareTo;
构造器引用
和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。
抽象方法的返回值类型即为构造器所属的类的类型
//构造器引用
//Supplier中的T get()
Supplier<Employee> sup = () -> new Employee();
Supplier<Employee> sup1 = Employee :: new;
数组引用
//数组引用
//Function中的R apply(T t)
Function<Integer,String[]> fun = length -> new String[length];
Function<Integer,String[]> fun1 = String[] :: new;
Stream API
Stream关注的是对数据的运算,与CPU打交道
集合关注的是数据的存储,与内存打交道
Stream不会自己存储元素
Stream不会改变源对象。相反,会返回一个持有结果的新Stream
Stream操作是延迟进行的,意味着会等到需要结果的时候才执行
Stream操作三个步骤:
①Stream的实例化
②一系列中间操作
③终止操作
注意:1)一旦执行终止操作,就执行中间操作链,并产生结果 2)中间操作链是一次性的
//创建Stream方式一:通过集合
List<Employee> employees = EmployeeData.getEmployees();
//default Stream<E> stream():返回一个顺序流
Stream<Employee> stream = employees.stream();
//default Stream<E> parallelStream():返回一个并行流
Stream<Employee> stream1 = employees.parallelStream();
//创建Stream方式二:通过数组
int[] arr = new int[]{1, 2, 3, 4, 5, 6};
//调用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()
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
//创建Stream方式四:创建无限流
//迭代
//public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
//遍历前10个偶数
Stream.iterate(0, t -> t-2).limit(10).forEach(System.out::println);
//生成
//public static<T> Stream<T> generate(Supplier<T> s)
Stream.generate(Math::random).limit(10).forEach(System.out::println);
中间操作
①筛选和切片
filter(Predicate p)
:接收lambda,从流中排除某些元素
distinct()
:筛选,通过流所生成元素的hashCode()
和equals()
去除重复元素
limit(long maxSize)
:截断流,使其元素不超过给定数量
skip(long n)
:跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)
互补
②映射
map(Function f)
:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射为一个新的元素
mapToDouble(ToDoubleFunction f)
:接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream
mapToInt(ToIntFunction f)
:接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream
mapToLong(ToLongFunction f)
:接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream
flatMap(Function f)
:接收一个函数作为参数,将流中的每个值都换为另一个流,然后把所有的流连接成一个流
③排序
sorted()
:产生一个新流,其中按自然顺序排序
sorted(Comparator com)
:产生一个新流,其中按比较器顺序排序
终止操作
①匹配和查找
allMatch(Predicate p)
:查找是否匹配所有元素
anyMatch(Predicate p)
:查找是否至少匹配一个元素
noneMatch(Predicate p)
:查找是否没有匹配所有元素
findFirst()
:返回第一个元素
findAny()
:返回当前流中的任意元素
count()
:返回流中元素总数
max(Comparator c)
:返回流中最大值
min(Comparator c)
:返回流中最小值
forEach(Consumer c)
:内部迭代(使用Collection接口需要用户去迭代,称为外部迭代。相反,Stream API使用内部迭代)
②归约
reduce(T iden, BinaryOperator b)
:可以将流中元素反复结合起来,得到一个值,返回T
reduce(BinaryOperator b)
:可以将流中元素反复结合起来,得到一个值,返回Optional<T>
③收集
collect(Collector c)
:将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
Optional类
创建Optional类对象:
Optional.of(T t)
:创建一个Optional实例,t必须非空
Optional.empty()
:创建一个空的Optional实例
Optional.ofNullable(T t)
:t可以为null
判断Optional容器中是否包含对象:
boolean isPresent()
:判断是否包含对象
void ifPresent(Consumer<? super T> consumer):如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它
获取Optional容器的对象:
T get()
:如果调用对象包含值,返回该值,否则抛异常
T orElse(T other)
:如果有值则将其返回,否则返回指定的other对象
T orElseGet(Supplier<? extends T> other)
:如果有值则将其返回,否则返回由Supplier接口实现提供的对象
T orElseThrow(Supplier<? extends X> exceptionSupplier)
:如果有值则将其返回,否则抛出由Supplier接口实现提供的异常
Java9、10、11新特性: