当前位置: 首页 > news >正文

Java进阶之新特性

Java新特性

参考

官网:https://docs.oracle.com/en/

image-20231213204804081

image-20210110173844927

JDK5新特性

1.自动装箱与拆箱

自动装箱的过程:每当需要一种类型的对象时,这种基本类型就自动地封装到与它相同类型的包装类中。

自动拆箱的过程:每当需要一个值时,被包装对象中的值就被自动地提取出来,没必要再去调用intValue()和doubleValue()方法。

自动装箱,只需将该值赋给一个类型包装器引用,java会自动创建一个对象。

自动拆箱,只需将该对象值赋给一个基本类型即可。

java——类的包装器

类型包装器有:Double,Float,Long,Integer,Short,Character和Boolean

2.枚举

把集合里的对象元素一个一个提取出来。枚举类型使代码更具可读性,理解清晰,易于维护。枚举类型是强类型的,从而保证了系统安全性。而以类的静态字段实现的类似替代模型,不具有枚举的简单性和类型安全性。

简单的用法:JavaEnum简单的用法一般用于代表一组常用常量,可用来代表一类相同类型的常量值。

复杂用法:Java为枚举类型提供了一些内置的方法,同事枚举常量还可以有自己的方法。可以很方便的遍历枚举对象。

3.静态导入

通过使用 import static,就可以不用指定 Constants 类名而直接使用静态成员,包括静态方法。

import xxxx 和 import static xxxx的区别是前者一般导入的是类文件如import java.util.Scanner;后者一般是导入静态的方法,import static java.lang.System.out。

4.可变参数(Varargs)

可变参数的简单语法格式为:

methodName([argumentList], dataType… argumentName);

5.内省

内省是Java语言对Bean类属性、事件的一种缺省处理方法。例如类A中有属性name,那我们可以通过getName,setName来得到其值或者设置新的值。通过getName/setName来访问name属性,这就是默认的规则。Java中提供了一套API用来访问某个属性的getter /setter方法,通过这些API可以使你不需要了解这个规则(但你最好还是要搞清楚),这些API存放于包java.beans中。

一 般的做法是通过类Introspector来获取某个对象的BeanInfo信息,然后通过BeanInfo来获取属性的描述器 (PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后我们就可以通过反射机制来调用这些方法。

6.泛型(Generic)

C++ 通过模板技术可以指定集合的元素类型,而Java在1.5之前一直没有相对应的功能。一个集合可以放任何类型的对象,相应地从集合里面拿对象的时候我们也不得不对他们进行强制得类型转换。引入了泛型,它允许指定集合里元素的类型,这样你可以得到强类型在编译时刻进行类型检查的好处。

7.For-Each循环

For-Each循环得加入简化了集合的遍历。假设我们要遍历一个集合对其中的元素进行一些处理。

JDK7新特性

1.switch对String字符串的支持

2.泛型实例化类型自动推断

import java.util.ArrayList;
import java.util.List;public class HelloWord {public static void main(String[] args) {//jdk7之前,写法List<String> list1 = new ArrayList<String>();//jdk7之后,写法List<String> list2 = new ArrayList<>();}
}

3.增加一些获取环境信息的工具方法

File System.getJavaIoTempDir() // IO临时文件夹File System.getJavaHomeDir() // JRE的安装目录File System.getUserHomeDir() // 当前用户目录File System.getUserDir() // 启动java进程时所在的目录

4.Boolean类型反转,空指针安全,参与位运算

Boolean Booleans.negate(Boolean booleanObj)True => False , False => True, Null => Nullboolean Booleans.and(boolean[] array)boolean Booleans.or(boolean[] array)boolean Booleans.xor(boolean[] array)boolean Booleans.and(Boolean[] array)boolean Booleans.or(Boolean[] array)boolean Booleans.xor(Boolean[] array)

5.两个char间的equals

boolean Character.equalsIgnoreCase(char ch1, char ch2)

6.安全加减乘除

int Math.safeToInt(long value)int Math.safeNegate(int value)long Math.safeSubtract(long value1, int value2)long Math.safeSubtract(long value1, long value2)int Math.safeMultiply(int value1, int value2)long Math.safeMultiply(long value1, int value2)long Math.safeMultiply(long value1, long value2)long Math.safeNegate(long value)int Math.safeAdd(int value1, int value2)long Math.safeAdd(long value1, int value2)long Math.safeAdd(long value1, long value2)int Math.safeSubtract(int value1, int value2)

7.对Java集合(Collentions)的增加

   List<String> list=["item"]; //向List集合中添加元素String item=list[0]; //从List集合中获取元素Set<String> set={"item"}; //向Set集合对象中添加元素Map<String,Integer> map={"key":1}; //向Map集合中添加对象int value=map["key"]; //从Map集合中获取对象

8.数值可加下划线

例如:int one_million = 1_000_000;

9.支持二进制面值

例如:int binary = 0b1001_1001;

10.简化可变参数方法的调用

当程序员试图使用一个不可具体化的可变参数并调用一个varargs (可变)方法时,编辑器会生成一个“非安全操作”的警告。

11.在try catch异常扑捉中,一个catch可以写多个异常类型,用”|”隔开

try {......
} catch(ClassNotFoundException|SQLException ex) {ex.printStackTrace();
}

12.try-with-resource

try(InputStream in=new FileInputStream(new File("d:\\hello.jpeg"))){}catch (Exception e) {	}

12.自定义关闭类

JDK8新特性

Lambda表达式

它的用处就是简化接口只有一个抽象方法时,匿名内部类语法的复杂程度。

也就是说,一切的Lambda表达式,其实都可以写成匿名内部类。

说到Lambda表达式,我们就要先看下匿名内部类,如下就是一个使用Runnable的匿名内部类,由于匿名内部类的写法有时候显得比较复杂,因此才有了Lambda表达是对其进行简化

public static void main(String [] args){//匿名内部类,写法:new Thread(new Runnable(){@Overrideprivate void run(){System.out.println('xxxx') }})//lambda表达式写法new Thread(() -> System.out.println('xxxx') )
}

只有一个抽象方法的接口,该接口的匿名内部类,必须重写且只能重写该方法。那么,我们完完全全没有必要,去关注该方法的【权限修饰符,方法签名和返回值】了。我们只用关注【参数 + 方法体】即可。

Lambda表达式,也可以成为闭包,它是推动Java8发布的最重要的新特性。

Lambda表达式,允许函数作为一个方法的参数,即函数作为参数传递给方法。

Lambda表达式,可以使代码更加简洁紧凑。

语法

Lambda表达式的语法格式如下:

(parameters) -> expression

(parameters) -> {statements;}

特征
  1. 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  2. 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  3. 可选的大括号:如果主体包含一个语句,就不需要使用大括号。
  4. 可选的返回关键字:如果主体只有一个表达式返回值时,编译器会自动返回值;如果主体有多个表达式时,大括号内需要用return显示返回一个值。
实例

//1.不需要参数,返回值为 5

() -> 5

//2.接受一个参数,返回值为其2倍

x -> 2*x

//3.接受2个参数,返回他们的和

(x,y) -> x+y

//4.接受2个参数,带参数类型

(int x,int y) -> x*y

//5.接受一个String对象,并在控制台打印

(String str) -> System.out.print(str);

public class HelloWord {public static void main(String[] args) {//可选类型声明System.out.println("可选类型声明-----------------------------");MathOperation addition1 = (a,b) -> a * b;System.out.println(addition1.operation(2, 3));MathOperation addition2 = (int a,int b) -> a * b;System.out.println(addition2.operation(2, 3));//可选参数圆括号System.out.println("可选参数圆括号-----------------------------");MathSystem mathSystem = str -> System.out.println(str);mathSystem.system("同志们辛苦了");MathSystem mathSystem1 = (str) -> System.out.println(str);mathSystem1.system("为人民服务");//可选的大括号System.out.println("可选的大括号-----------------------------");MathSystem mathSystem2 = str -> System.out.println(str);MathSystem mathSystem3 = str -> {System.out.println(str);};//可选的返回关键字System.out.println("可选的返回关键字-----------------------------");MathOperation mathOperation =  (x,y) -> {return x * y;};MathOperation mathOperation2 =  (x,y) ->  x * y;}interface MathOperation{int operation(int x,int y);}interface MathSystem{void system(String str);}
}

可选类型声明-----------------------------
6
6
可选参数圆括号-----------------------------
同志们辛苦了
为人民服务
可选的大括号-----------------------------

变量作用域

Lambda表达式只能引用final修饰的局部变量,这就是说不能在lambda表达式内部修改定义在外城的局部变量,否则会编译错误。

Lambda表达式的局部变量可以不用声明为final,但是必须不可被后面的代码修改(即隐性的具有final的语义)

@FunctionalInterface

JDK8还提供了一个注解,@FunctionalInterface,这个注解和@Override是差不多的,都是编译器检验注解。
它是用来干嘛的呢?对,其实猜都知道了,他就是来检查该接口是不是只有一个抽象方法的。如果是的话,他才不会报错。所以,在JDK8以后,看见标注了@@FunctionalInterface的接口,就大胆的写Lambda来代替匿名内部类吧!

函数式接口

四大函数式接口

img

Function接口
  /*** Function接口*/public static void testFunction(){Function<String,Integer> f1 = s -> (s == null) ? 0 : s.length();System.out.println(f1.apply("abcd"));}
Consumer接口
/*** Consumer接口*/public static void testConsumer(){//匿名内部类的方式Consumer<String> c1 = new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}};//lambda表达式的方式Consumer<String> c2 = s -> System.out.println(s);c1.accept("abcde");c2.accept("张三");List<String> list = new ArrayList<String>(){{this.add("1");this.add("2");this.add("3");this.add("4");this.add("5");}};//以前迭代集合System.out.println("-----------以前迭代集合----------");for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}//增强版System.out.println("-----------增强版----------");for (String s : list) {System.out.println(s);}//匿名内部类System.out.println("-----------匿名内部类----------");list.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});//lambda表达式System.out.println("-----------lambda表达式----------");list.forEach(s -> System.out.println(s));//方法引用System.out.println("-----------方法引用----------");list.forEach(System.out::println);}
Supplier接口
/*** Supplier接口*/
public static void testSupplier(){Supplier<String> s = () -> "abcd";
}
Predicate接口
/*** Predicate接口*/
public static void testPredicate(){Predicate<Integer> p = s -> s > 4;System.out.println(p.test(3));
}
扩展接口

扩展模式:

  • 泛型参数特定化
  • 泛型参数一致化
消费型接口-扩展接口

img

供给型接口-扩展接口

img

函数型接口-扩展接口

img

断言型接口-扩展接口

img

接口默认方法

简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。

为什么要有这个特性?

首先,之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类,目前的 java 8 之前的集合框架没有 foreach 方法,通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现。然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现。所以引进的默认方法。他们的目的是为了解决接口的修改与现有的实现不兼容的问题。

语法
public interface Vehicle {default void print(){System.out.println("我是一辆车!");}
}
多个默认方法

一个接口有默认方法,考虑这样的情况,一个类实现了多个接口,且这些接口有相同的默认方法,以下实例说明了这种情况的解决方法:

public interface Vehicle {default void print(){System.out.println("我是一辆车!");}
}public interface FourWheeler {default void print(){System.out.println("我是一辆四轮车!");}
}

第一个解决方案是创建自己的默认方法,来覆盖重写接口的默认方法:

public class Car implements Vehicle, FourWheeler {default void print(){System.out.println("我是一辆四轮汽车!");}
}

第二种解决方案可以使用 super 来调用指定接口的默认方法:

public class Car implements Vehicle, FourWheeler {public void print(){Vehicle.super.print();}
}

接口静态方法

Java 8 的另一个特性是接口可以声明(并且可以提供实现)静态方法。例如:

public interface Vehicle {default void print(){System.out.println("我是一辆车!");}// 静态方法static void blowHorn(){System.out.println("按喇叭!!!");}
}public class Java8Tester {public static void main(String args[]){Vehicle vehicle = new Car();vehicle.print();}
}

方法引用

方法引用通过方法的名字来指定一个方法。

方法引用使用一对冒号::

构造器引用

构造器引用:语法是 Class::new;或者更一般的 Class::new;

//构造器引用
Car car1 = Car.create(()->new Car());
Car car2 = Car.create(Car::new);
System.out.println(car1.name);
System.out.println(car2.name);
静态方法引用

静态方法引用:语法是 Class::static_method;

final Car car = Car.create( Car::new );
final List< Car > cars = Arrays.asList( car );
cars.forEach( Car::collide );
类的任意对象的方法引用

类的任意对象的方法引用:语法是 Class::method;

太难以理解了。难以理解的东西,也难以维护。建议还是不要用该种方法引用。
实例方法要通过对象来调用,方法引用对应Lambda,Lambda的第一个参数会成为调用实例方法的对象。

cars.forEach( Car::repair );
对象的方法引用

对象的方法引用:语法是 instance::method;

final Car police = Car.create( Car::new );
cars.forEach( police::follow );
public static class Car {public static Car create( final Supplier< Car > supplier ) {return supplier.get();}              public static void collide( final Car car ) {System.out.println( "Collided " + car.toString() );}public void follow( final Car another ) {System.out.println( "Following the " + another.toString() );}public void repair() {   System.out.println( "Repaired " + this.toString() );}
}
实例
/*** 1. instanceName::methodName  实例对象::实例方法名** 方法引用的注意事项:* 1.被引用的方法,参数要和接口中抽象方法的参数一样,*      如 now:: setTime会报错,因为这个方法有参数,而Supplier接口的get()方法没有参数。* 2.当接口抽象方法有返回值时,被引用的方法也必须有返回值*/private static void test01() {// 创建一个对象Date date = new Date();//一般写法System.out.println(date.getTime());// Lambda表达式写法Supplier<Long> supplier1 = () -> date.getTime();System.out.println(supplier1.get());// 方法引用写法Supplier<Long> supplier2 = date::getTime;System.out.println(supplier2.get());}/*** 2. ClassName::methodName 类名::实例方法名*/private static void test02() {//取字符串的长度String str = "abdc";//一般写法System.out.println(str.length());//匿名内部类Function<String,Integer> f1 = new Function<String, Integer>() {@Overridepublic Integer apply(String s) {return s.length();}};System.out.println(f1.apply(str));//Lambda表达式写法Function<String,Integer> f2 = s -> s.length();System.out.println(f2.apply(str));//方法引用写法Function<String,Integer> f3 = String::length;System.out.println(f3.apply(str));}/*** 3. ClassName::staticMethodName 类名::静态方法名*/private static void test03() {long l = System.currentTimeMillis();//一般写法System.out.println(l);// Lambda表达式写法Supplier<Long> supplier1 = () -> System.currentTimeMillis();System.out.println(supplier1.get());// 方法引用写法Supplier<Long> supplier2 =  System::currentTimeMillis;System.out.println(supplier2.get());}/*** 4. ClassName::new    类名::构造方法名*/private static void test04() {//无参构造// Lambda表达式写法Supplier<User> supplier1 = () -> new User();System.out.println(supplier1.get());// 方法引用写法Supplier<User> supplier2 = User::new;System.out.println(supplier2.get());//有参构造// Lambda表达式写法BiFunction<String,Integer,User> bf1 = (name, age) -> new User(name,age);User user1 = bf1.apply("张三", 12);System.out.println(user1);// 方法引用写法BiFunction<String,Integer,User> bf2 = User::new;User user2 = bf1.apply("李四", 13);System.out.println(user2);}

Stream

Steam流式思想概述

注意:Stream和IO流(InputStream/OutputStream)没有任何关系,请暂时忘记对传统IO流的固有印象!

Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工处理。

Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。
Stream API能让我们快速完成许多复杂的操作,如筛选、切片、映射、查找、去除重复,统计,匹配和归约。

Stream流的生成操作
Stream.of()

of方法,其生成的Stream是有限长度的,Stream的长度为其内的元素个数。

Stream stream1 = Stream.of("2","3","1");
stream1.forEach(System.out::println);
Stream.generate()

generator方法,返回一个无限长度的Stream,其元素由Supplier接口的提供。在Supplier是一个函数接口,只封装了一个get()方法,其用来返回任何泛型的值,该结果在不同的时间内,返回的可能相同也可能不相同,没有特殊的要求。

Stream stream2 = Stream.generate(Math::random);
stream2.limit(3).forEach(System.out::println);
Stream.iterate()

iterate方法,其返回的也是一个无限长度的Stream,与generate方法不同的是,其是通过函数f迭代对给指定的元素种子而产生无限连续有序Stream,其中包含的元素可以认为是:seed,f(seed),f(f(seed))无限循环。

final Stream<Integer> iterate = Stream.iterate(1, item -> item + 1);
iterate.forEach(System.out::println);
Stream.empty()

empty方法返回一个空的Stream。

Collection接口的stream()或parallelStream()方法
List list = Arrays.asList("2","1","3");
final Stream stream = list.stream();
stream.forEach(System.out::println);
Arrays.stream(array, from, to)

在Arrays类,封装了一些列的Stream方法,不仅针对于任何类型的元素采用了泛型,更对于基本类型作了相应的封装,以便提升Stream的处理效率。

Arrays.stream(new String[]{"2","3"}).forEach(System.out::println);
Stream.concat()

静态的Stream.concat()方法将两个流连接起来,返回一个新的Stream

final Stream<String> concat = Stream.concat(Stream.of("3", "2"), Stream.of("5", "9"));
concat.forEach(System.out::println);
其他

Pattern接口的splitAsStream(input)方法
静态的Files.lines(path)、Files.lines(path, charSet)方法

Map接口的Stream获取

但是Map接口别没有实现Collection接口,那这时怎么办呢?这时我们可以根据Map获取对应的key value的集合。

public static void main(String[] args) {Map<String,Object> map = new HashMap<>();Stream<String> stream = map.keySet().stream(); // keyStream<Object> stream1 = map.values().stream(); // valueStream<Map.Entry<String, Object>> stream2 = map.entrySet().stream(); // entry
}
Stream操作分类

image-20220114162022180

Stream上的所有操作分为两类:中间操作和结束操作,中间操作只是一种标记,只有结束操作才会触发实际计算。中间操作又可以分为无状态的(Stateless)和有状态的(Stateful),无状态中间操作是指元素的处理不受前面元素的影响,而有状态的中间操作必须等到所有元素处理之后才知道最终结果,比如排序是有状态操作,在读取所有元素之前并不能确定排序结果;结束操作又可以分为短路操作和非短路操作,短路操作是指不用处理全部元素就可以返回结果,比如找到第一个满足条件的元素。之所以要进行如此精细的划分,是因为底层对每一种情况的处理方式不同。

中间操作(Intermediate)
distinct

distinct方法以达到去除掉原Stream中重复的元素,生成的新Stream中没有没有重复的元素。

final Stream<String> concat = Stream.concat(Stream.of("3", "2"), Stream.of("3", "2","5", "9"));
//concat.forEach(System.out::print);//3 2 3 2 5 9
concat.distinct().forEach(System.out::print);//3 2 5 9
filter

filter方法对原Stream按照指定条件过滤,在新建的Stream中,只包含满足条件的元素,将不满足条件的元素过滤掉。

final Stream<String> concat = Stream.concat(Stream.of("3", "2"), Stream.of("3", "2","5", "9"));
concat.filter(item -> !item.equals("3") ).forEach(System.out::print);//2 2 5 9
map

map方法将对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。为了提高处理效率,官方已封装好了,三种变形:mapToDouble,mapToInt,mapToLong。其实很好理解,如果想将原Stream中的数据类型,转换为double,int或者是long是可以调用相对应的方法。

final Stream<String> concat = Stream.concat(Stream.of("a", "b"), Stream.of("hello", "c","d", "e"));
concat.map(item -> item.toUpperCase()+" " ).forEach(System.out::print);//A B HELLO C D E Arrays.stream(new User[]{new User("张三1",14),new User("张三2",38),new User("张三3",28)}).map(item -> item.getAge()).forEach(System.out::println);
flatMap

flatMap方法与map方法类似,都是将原Stream中的每一个元素通过转换函数转换,不同的是,该换转函数的对象是一个Stream,也不会再创建一个新的Stream,而是将原Stream的元素取代为转换的Stream。如果转换函数生产的Stream为null,应由空Stream取代。flatMap有三个对于原始类型的变种方法,分别是:flatMapToInt,flatMapToLong和flatMapToDouble。

Stream.of(1, 2, 3).flatMap(integer -> Stream.of(integer * 10)).forEach(System.out::println);// 打印结果// 10,20,30
peek

peek方法生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数(Consumer实例),新Stream每个元素被消费的时候都会执行给定的消费函数,并且消费函数优先执行

Arrays.stream(new User[]{new User("张三1",14),new User("张三2",38),new User("张三3",28)})
.map(item -> item.getAge()).peek(item -> System.out.println("accept : "+item)).forEach(System.out::println);
/**输出结果:accept : 1414accept : 3838accept : 2828*/
skip

skip方法将过滤掉原Stream中的前N个元素,返回剩下的元素所组成的新Stream。如果原Stream的元素个数大于N,将返回原Stream的后(原Stream长度-N)个元素所组成的新Stream;如果原Stream的元素个数小于或等于N,将返回一个空Stream。

Arrays.stream(new User[]{new User("张三1",14),new User("张三2",38),new User("张三3",28)})
.map(item -> item.getAge()).skip(2).forEach(System.out::println);
/**输出结果:28*/
sorted

sorted方法将对原Stream进行排序,返回一个有序列的新Stream。sorterd有两种变体sorted(),sorted(Comparator),前者将默认使用Object.equals(Object)进行排序,而后者接受一个自定义排序规则函数(Comparator),可按照意愿排序。

Arrays.stream(new User[]{new User("张三1",14),new User("张三2",38),new User("张三3",28)})
.map(item -> item.getAge()).sorted().forEach(System.out::println);
/**输出结果:142838*/Arrays.stream(new User[]{new User("张三1",14),new User("张三2",38),new User("张三3",28)}).map(item -> item.getAge()).sorted(new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2-o1;}}).forEach(System.out::println);Arrays.stream(new User[]{new User("张三1",14),new User("张三2",38),new User("张三3",28)}).map(item -> item.getAge()).sorted(Test::compare).forEach(System.out::println);
class Test2{public static int compare(Integer o1,Integer o2){return o2-o1;}
}
/**输出结果:382814*/
limit

limit方法将截取原Stream,截取后Stream的最大长度不能超过指定值N。如果原Stream的元素个数大于N,将截取原Stream的前N个元素;如果原Stream的元素个数小于或等于N,将截取原Stream中的所有元素。

Stream.of(1, 2, 3,4,5).limit(2).forEach(System.out::println);
终结操作(Terminal)
count

count方法将返回Stream中元素的个数。

final Stream<String> concat = Stream.concat(Stream.of("3", "2"), Stream.of("3", "2","5", "9"));
final long count = concat.filter(item -> !item.equals("3")).count();//2 2 5 9
System.out.println(count);//打印结果 4
max

max方法根据指定的Comparator,返回一个Optional,该Optional中的value值就是Stream中最大的元素。至于Optional是啥,后续再做介绍吧。

final Optional<Integer> max = Stream.of(1, 2, 5, 8).max(Test2::compare);
System.out.println("最大值为:"+max.get());//打印结果 8class Test2{public static int compare(Integer o1,Integer o2){return o1-o2;}
}
min

min方法根据指定的Comparator,返回一个Optional,该Optional中的value值就是Stream中最小的元素。至于Optional是啥,后续再做介绍吧。

final Optional<Integer> min = Stream.of(1, 2, 5, 8).min(Test2::compare);
System.out.println("最小值为:"+min.get());//打印结果 1class Test2{public static int compare(Integer o1,Integer o2){return o1-o2;}
}
reduce

是用来执行聚合操作的

Stream.of(1, 2, 5, 8).reduce((a,b)-> a*b ).ifPresent(System.out::println);// 80
final Integer integer = Stream.of(1, 2, 5, 8).reduce((a, b) -> a * b).get();// 80
match

如果需要判断数据是否匹配指定的条件,可以使用match相关的方法

boolean anyMatch(Predicate<? super T> predicate); // 元素是否有任意一个满足条件
boolean allMatch(Predicate<? super T> predicate); // 元素是否都满足条件
boolean noneMatch(Predicate<? super T> predicate); // 元素是否都不满足条件
forEach

forEach方法前面已经用了好多次,其用于遍历Stream中的所元素,避免了使用for循环,让代码更简洁,逻辑更清晰。

Arrays.stream(new User[]{new User("张三1",14),new User("张三2",38),new User("张三3",28)}).map(item -> item.getAge()).sorted(Test2::compare).forEach(System.out::println);
forEachOrdered

forEachOrdered方法与forEach类似,都是遍历Stream中的所有元素,不同的是,如果该Stream预先设定了顺序,会按照预先设定的顺序执行(Stream是无序的),默认为元素插入的顺序。

Stream.of(5,2,1,4,3).forEachOrdered(integer -> {System.out.println("integer:"+integer);}); 
Collectors

对流中元素执行一个可变汇聚操作。是一个终止操作。比如:将流中的元素放入到一个List集合当中,将流中的元素进行分组、分区,求和等等操作。接受一个收集器Collector对象。

Stream中有两个个方法collect和collectingAndThen用于对流中的数据进行处理,可以对流中的数据进行聚合操作,如:

将流中的数据转成集合类型: toList、toSet、toMap、toCollection
将流中的数据(字符串)使用分隔符拼接在一起:joining
对流中的数据求最大值maxBy、最小值minBy、求和summingInt、求平均值averagingDouble
对流中的数据进行映射处理 mapping
对流中的数据分组:groupingBy、partitioningBy
对流中的数据累计计算:reducing
<R, A> R collect(Collector<? super T, A, R> collector);

// collectingAndThen : 将流中的数据通过Collector计算,最终的结果在通过Function再最终处理一下
public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream,
Function<R,RR> finisher);
Collectors

 
public final class Collectors {// 转换成集合public static <T> Collector<T, ?, List<T>> toList();public static <T> Collector<T, ?, Set<T>> toSet();public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,Function<? super T, ? extends U> valueMapper);public static <T, C extends Collection<T>> Collector<T, ?, C> toCollection(Supplier<C> collectionFactory);// 拼接字符串,有多个重载方法                                  public static Collector<CharSequence, ?, String> joining(CharSequence delimiter);   public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,CharSequence prefix,CharSequence suffix);      // 最大值、最小值、求和、平均值                                                         public static <T> Collector<T, ?, Optional<T>> maxBy(Comparator<? super T> comparator);public static <T> Collector<T, ?, Optional<T>> minBy(Comparator<? super T> comparator);public static <T> Collector<T, ?, Integer> summingInt(ToIntFunction<? super T> mapper);      public static <T> Collector<T, ?, Double> averagingDouble(ToDoubleFunction<? super T> mapper);                   // 分组:可以分成true和false两组,也可以根据字段分成多组                                 public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier);// 只能分成true和false两组public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate);// 映射public static <T, U, A, R> Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper,Collector<? super U, A, R> downstream);public static <T, U> Collector<T, ?, U> reducing(U identity,Function<? super T, ? extends U> mapper,BinaryOperator<U> op);
}
流转换成集合
Stream.of(1,2,3,5,4).collect(Collectors.toList()).forEach(System.out::println);System.out.println("------------------------------");final Map<Integer, Integer> collect = Stream.of(4, 32, 2).collect(Collectors.toMap(key -> key, value -> value));final Set<Map.Entry<Integer, Integer>> entries = collect.entrySet();entries.forEach(System.out::println);
集合元素拼接
final String collect = Stream.of("1", "b", "d", "中", "3").collect(Collectors.joining(","));System.out.println(collect);//1,b,d,中,3System.out.println("------------------------------");final String collect1 = Stream.of("1", "2").collect(Collectors.collectingAndThen(Collectors.joining("|"), x -> x + "X"));System.out.println(collect1);//1|2X
元素聚合
final Integer collect = Stream.of(4, 5, 2, 7).collect(Collectors.collectingAndThen(Collectors.maxBy((a, b) -> a - b), Optional::get));
System.out.println(collect);//
分组
 List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);// 奇偶数分组:奇数分一组,偶数分一组// groupingBy(Function<? super T, ? extends K> classifier) 参数是Function类型,Function返回值可以是要分组的条件,也可以是要分组的字段// 返回的结果是Map,其中key的数据类型为Function体中计算类型,value是List<T>类型,为分组的结果Map<Boolean, List<Integer>> result = list.stream().collect(Collectors.groupingBy(item -> item % 2 == 0));// {false=[1, 3, 5, 7, 9], true=[2, 4, 6, 8, 10]}System.out.println(result);
累计操作
// sum: 是每次累计计算的结果,b是Function的结果public static void main(String[] args) {Integer collect = Stream.of(1, 3, 4).collect(Collectors.reducing(0, x -> x + 1, (sum, b) -> {System.out.println(sum + "-" + b);return sum + b;}));System.out.println(collect);
}

Time API

Optional 类

介绍

什么是Optional:Optional是jdk8推出的一个新类,为了减少代码中的判空代码,使代码更加干净整洁优雅,不提高执行效率。

使用场景:当一个对象需要进行判空代码处理的时候,就可以考虑使用Optional。

Optional类作用:可以将Optional理解为一个容器类,其内部仅能存放一个对象元素,Optional提供了一系列的工具方法进行判断、操作存放的元素。

使用语法
方法声明介绍
Optional empty();创建一个空的Optional对象。
Optional of(T value);使用一个非空的值创建Optional对象,传入null将抛出异常。
Optional ofNullable(T value);使用任意值创建Optional对象,若值为null,则创建一个空的Optional对象。
T get();返回Optional对象中的值,若为null,则抛出异常。
boolean isPresent();若Optional对象中的值不为null,则返回true,否则返回false。
void ifPresent(Consumer<? super T> consumer);若Optional对象中的值不为null,则执行Consumer对象,否则不执行。
Optional filter(Predicate<? super T> predicate);执行Predicate对象,执行结果返回true,返回Optional对象中的值
执行结果返回false或Optional对象中的值为空都返回空的Optional对象。
Optional map(Function<? super T, ? extends U> mapper);执行Function对象,Function的入参为Optional对象中的值,返回值将被包装成Optional返回。
若原本Optional中的值为null,则直接返回空的Optional对象。
Optional flatMap(Function<? super T, Optional> mapper);功能和map方法一样,差别在于执行的Function对象需要返回Optional对象,否则抛出异常,返回对象为null也将抛出异常。
T orElse(T other);若Optional对象中有值,则将值返回,否则返回给定值other值。
T orElseGet(Supplier<? extends T> other);若Optional对象中有值,则将值返回,否则将执行Supplier对象并返回执行结果。
T orElseThrow(Supplier<? extends X> exceptionSupplier);若Optional对象中有值,则将值返回,否则将执行Supplier对象并将返回值作为异常抛出。
语法演示
初始化
public class Demo {public static void main(String[] args) {//创建空的OptionalOptional<Object> emptyOptional = Optional.empty();//使用of创建Optional<String> hello = Optional.of("hello");//正常Optional<Object> objectOptional = Optional.of(null);//运行时抛出异常//使用ofNullable创建Optional<String> hello2 = Optional.ofNullable("hello");//正常Optional<Object> objectOptional2 = Optional.ofNullable(null);//正常}}
获取Optional中的对象
get
public class Demo {public static void main(String[] args) {Optional<String> helloOptional = Optional.ofNullable("hello");Optional<String> nullOptional = Optional.ofNullable(null);//使用get获取Optional中的对象System.out.println(helloOptional.get());/*** 运行结果:* hello*/System.out.println(nullOptional.get());/*** 运行结果:* 抛出运行时异常 java.util.NoSuchElementException*/}}
orElse
public class Demo {public static void main(String[] args) {Optional<String> helloOptional = Optional.ofNullable("hello");Optional<String> nullOptional = Optional.ofNullable(null);//执行orElseString result1 = helloOptional.orElse("val is null");System.out.println(result1);/*** 运行结果:* hello*/String result2 = nullOptional.orElse("val is null");System.out.println(result2);/*** 运行结果:* val is null*/}
}
orElseGet
public class Demo {public static void main(String[] args) {Optional<String> helloOptional = Optional.ofNullable("hello");Optional<String> nullOptional = Optional.ofNullable(null);//执行orElseString result1 = helloOptional.orElseGet(()->{return "val is null";});System.out.println(result1);/*** 运行结果:* hello*/String result2 = nullOptional.orElseGet(()->{return "val is null";});System.out.println(result2);/*** 运行结果:* val is null*/}
}
判断Optional中的值
isPresent()
public class Demo {public static void main(String[] args) {Optional<String> helloOptional = Optional.ofNullable("hello");Optional<String> nullOptional = Optional.ofNullable(null);//使用isPresent判断Optional中的值是否为nullSystem.out.println(helloOptional.isPresent());/*** 运行结果:* true*/System.out.println(nullOptional.isPresent());/*** 运行结果:* false*/}}
ifPresent(Consumer<? super T> consumer)
public class Demo {public static void main(String[] args) {Optional<String> helloOptional = Optional.ofNullable("hello");Optional<String> nullOptional = Optional.ofNullable(null);//执行ifPresent(Consumer<? super T> consumer)方法helloOptional.ifPresent(str->{System.out.println("Optional中的值:"+str);});/*** 运行结果:* Optional中的值:hello*/nullOptional.ifPresent(str->{System.out.println("Optional中的值:"+str);});/*** 运行结果:* 因nullOptional中的对象为null,所以不执行Consumer对象*/}}
filter
public class Demo {public static void main(String[] args) {Optional<String> helloOptional = Optional.ofNullable("hello");Optional<String> nullOptional = Optional.ofNullable(null);//执行filter方法Optional<String> result1 = helloOptional.filter(str -> {if ("hello world".equals(str)) {return true;}return false;});System.out.println(result1.get());/*** 运行结果:* 返回空的Optional对象,执行get抛出运行时异常 java.util.NoSuchElementException*/Optional<String> result2 = helloOptional.filter(str -> {if ("hello".equals(str)) {return true;}return false;});System.out.println(result2.get());/*** 运行结果:* hello*/Optional<String> result3 = nullOptional.filter(str -> {return true;});System.out.println(result3.get());/*** 运行结果:* 因为nullOptional中的对象为null,所以不执行Predicate对象,直接返回空的Optional对象* 执行get抛出运行时异常 java.util.NoSuchElementException*/}}
map
public class Demo {public static void main(String[] args) {Optional<String> helloOptional = Optional.ofNullable("hello");Optional<String> nullOptional = Optional.ofNullable(null);//执行map方法Optional<String> result1 = helloOptional.map(str -> {if ("hello world".equals(str)) {return "你好世界";}return "unknown";});System.out.println(result1.get());/*** 运行结果:* unknown*/Optional<String> result2 = nullOptional.map(str -> {return "你好世界";});System.out.println(result2.get());/*** 运行结果:* 因nullOptional中的值为null,则map方法直接返回空的Optional对象* 执行get抛出运行时异常 java.util.NoSuchElementException*/}}
flatMap
public class Demo {public static void main(String[] args) {Optional<String> helloOptional = Optional.ofNullable("hello");Optional<String> nullOptional = Optional.ofNullable(null);//执行flatMap方法helloOptional.flatMap(str -> {return "unknown";});/*** 运行结果:* 编译阶段报错,因flatMap的Function对象需要返回一个Optional对象。*/Optional<String> unknown = helloOptional.flatMap(str -> {return Optional.ofNullable("unknown");});System.out.println(unknown.get());/*** 运行结果:* unknown*/}}
使用案例
class Person{private String name;private int age;private EduBack eduBack;//省略getter、setter
}class EduBack{private College college;private HighSchool highSchool;//省略getter、setter
}class College{private String name;//省略getter、setter
}class HighSchool{private String name;//省略getter、setter
}public class Demo {/*** 传统方式获取高校名称* @param person* @return*/public String getCollege(Person person){if(person==null){return null;}if(person.getEduBack()==null){return null;}if(person.getEduBack().getCollege()==null){return null;}return person.getEduBack().getCollege().getName();}/*** 使用Optional方式获取高中名称* @param person* @return*/public String getHighSchool(Person person) {String highSchoolName = Optional.ofNullable(person).map(p -> p.getEduBack()).map(edu -> edu.getHighSchool()).map(h -> h.getName()).orElse(null);return highSchoolName;}/*** 使用Optional方式获取高中名称(使用方法引用优化lambda)* @param person* @return*/public String getHighSchoolQuot(Person person){String highSchoolName = Optional.ofNullable(person).map(Person::getEduBack).map(EduBack::getHighSchool).map(HighSchool::getName).orElse(null);return highSchoolName;}public static void main(String[] args) {HighSchool highSchool = new HighSchool();highSchool.setName("高中学校");College college = new College();college.setName("高校学校");EduBack eduBack = new EduBack();eduBack.setCollege(college);eduBack.setHighSchool(highSchool);Person person = new Person();person.setName("张三");person.setEduBack(eduBack);Demo demo = new Demo();System.out.println(demo.getCollege(person));System.out.println(demo.getHighSchool(person));System.out.println(demo.getHighSchoolQuot(person));}
}

ll;
}
return person.getEduBack().getCollege().getName();
}

/*** 使用Optional方式获取高中名称* @param person* @return*/
public String getHighSchool(Person person) {String highSchoolName = Optional.ofNullable(person).map(p -> p.getEduBack()).map(edu -> edu.getHighSchool()).map(h -> h.getName()).orElse(null);return highSchoolName;
}/*** 使用Optional方式获取高中名称(使用方法引用优化lambda)* @param person* @return*/
public String getHighSchoolQuot(Person person){String highSchoolName = Optional.ofNullable(person).map(Person::getEduBack).map(EduBack::getHighSchool).map(HighSchool::getName).orElse(null);return highSchoolName;
}public static void main(String[] args) {HighSchool highSchool = new HighSchool();highSchool.setName("高中学校");College college = new College();college.setName("高校学校");EduBack eduBack = new EduBack();eduBack.setCollege(college);eduBack.setHighSchool(highSchool);Person person = new Person();person.setName("张三");person.setEduBack(eduBack);Demo demo = new Demo();System.out.println(demo.getCollege(person));System.out.println(demo.getHighSchool(person));System.out.println(demo.getHighSchoolQuot(person));
}

}


相关文章:

  • 中科视界,赋能文化产业新世界——千眼狼高速摄像机、DIC测量系统亮相第二十一届中国(深圳)国际文博会
  • VMIC PMV-5565PIORC-21000超高速光纤反射内存硬件参考
  • Argo CD 详解:从 GitOps 到持续交付的完整实践
  • Appium+python自动化(二)- 环境搭建—下
  • 鸿蒙 Initiated Worker with invalid NODE_OPTIONS env variable
  • N-gram语言模型原理与实战教程
  • Issac Lab安装
  • java I/O
  • SQLSERVER数据库表分区学习(未在项目上使用)
  • 地信GIS专业关于学习、考研、就业方面的一些问题答疑
  • HCIP-AI培养计划,成为新时代AI解决方案架构高级工程师
  • 【Dify学习笔记】:dify通过ollama加载DeepSeek-R1-32B模型无法加载!终于解决了!!
  • DL00786-基于RTDETR的水稻病害检测含完整数据集
  • C++函数封装和绑定
  • JWT了解
  • 有了CodeBuddy,10分钟上线MBTI测试网站
  • PiliPlus 非常好用的开源软件第三方B站哔哩哔哩 v1.1.3.35
  • upload-labs通关笔记-第18关文件上传之条件竞争
  • 文件操作和IO-3 文件内容的读写
  • QScrollArea内容增加后自动跳到底部
  • 做网站的数据库的设计/营销策划与运营公司
  • 个人网站与企业网站区别/免费推广平台
  • 怎样经营好一个网站/石家庄seo公司
  • 网站建设仟首先金手指13/网站定制
  • xv10相同网站/网络事件营销
  • 公司名高端大气不重名/优化设计答案