JDK1.8新特性

JDK1.8新特性

JDK1.8新特性简介

  • 速度更快 - 优化底层源码,比如HashMap、ConcurrentHashMap
  • 代码更少 - 添加新的语法Lambda表达式
  • 强大的Stream API
  • 便于并行
  • 最大化减少空指针异常 - Optional

Lambda表达式

简介

Lambda是一个匿名函数(方法), 允许把函数作为一个方法的参数 。利用Lambda表达式可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。

一般都是优化匿名内部类

基础语法

无参数、无返回值的抽象方法

public class Test1 {@Testpublic void test01() {
//		I1 i1 = new I1() {
//			@Override
//			public void method() {
//				System.out.println("传统使用匿名内部类的方式");
//			}
//		};
//		i1.method();I1 i1 = ()-> System.out.println("采用Lambda表达式的方式");i1.method();}
}
interface I1{public void method();//无参数、无返回值的抽象方法
}

一个参数、无返回值的抽象方法

public class Test1 {@Testpublic void test01() {I1 i1 = (x)-> System.out.println("采用Lambda表达式的方式 " + x);i1.method(1000);}
}
interface I1{public void method(int num1);//一个参数、无返回值的抽象方法
}

多个参数、无返回值的抽象方法

public class Test1 {@Testpublic void test01() {I1 i1 = (x,y,z)-> System.out.println("采用Lambda表达式的方式 " + x + y + z);i1.method(1000,2000,3000);}
}
interface I1{//多个参数、无返回值的抽象方法public void method(int num1,int num2,int num3);
}

多个参数、有返回值的抽象方法

public class Test1 {@Testpublic void test01() {I1 i1 = (x,y,z)-> x+y+z;int result = i1.method(1000,2000,3000);System.out.println(result);}
}
interface I1{//多个参数、有返回值的抽象方法public int method(int num1,int num2,int num3);
}
注意点
  1. 重写方法的形参只有一个时,可以不加小括号
  2. Lambda表达式当中不允许声明一个与局部变量同名的参数或者局部变量
  3. Lambda表达式中访问外层的局部变量,外层的局部变量自动变成隐式常量,默认添加final
  4. 重写方法的形参同时加类型或同时不加类型
public class Test1 {@Testpublic void test01() {int x;int num = 10;I1 i1 = x -> System.out.println(x + (num++));i1.method(1000);I2 i2 = (int x,int y) -> {int result = x+y;return result;};int result = i2.method(10, 20);System.out.println(result);}
}
interface I1{public void method(int num1);
}
interface I2{public int method(int num1,int num2);
}
练习

1.调用Collections.sort()方法,通过定制排序比较两个Student对象(先按年龄比较,年龄相同按照薪资比较),使用Lambda表达式作为参数传递

public class Test1 {@Testpublic void test01() {List<Student> stuList = Arrays.asList(new Student("张三", 28, 4800,Course.JAVA),new Student("李四", 36, 7200,Course.JAVA),new Student("王五", 19, 9600,Course.HTML),new Student("赵六", 42, 6100,Course.HTML),new Student("孙七", 23, 9600,Course.PYTHON),new Student("吴八", 31, 3000,Course.PYTHON));Collections.sort(stuList, (a,b)-> {if(a.getAge() == b.getAge()){return Double.compare(a.getSalary(),b.getSalary());}return a.getAge()-b.getAge();});for (Student stu : stuList) {System.out.println(stu);}}
}
enum Course{//课程枚举JAVA,HTML,PYTHON;
}
class Student{//学生类private String name;private int age;private double salary;private Course course;...
}

2.创建I1接口,创建抽象方法:public String getValue(String str),在测试类中编写方法使用接口作为参数,将一个字符串转为大写,并作为方法的返回值

public class Test1 {@Testpublic void test01() {String strHandler = strHandler("abc", x-> x.toUpperCase());System.out.println(strHandler);}public static String strHandler(String str,I1 i1){return i1.getValue(str);}
}
interface I1{public String getValue(String str);
}

3.创建I1<T,R>接口,泛型T为参数,R为返回值,创建抽象方法:public R add(T t1,T t2),在测试类中编写方法使用接口作为参数,计算两个long类型的和

public class Test1 {@Testpublic void test01() {Long addLong = addLong(100L, 200L, (x,y)-> x+y);System.out.println(addLong);}public static Long addLong(Long l1,Long l2,I1<Long,Long> i1){return i1.add(l1, l2);}
}
interface I1<T,R>{public R add(T t1,T t2);
}

函数式接口

简介

函数式接口是指仅仅只包含一个抽象方法的接口,jdk1.8提供了一个@FunctionalInterface注解来定义函数式接口,如果我们定义的接口不符合函数式的规范便会报错。配合Lambda表达式一起使用

四大核心函数式接口
函数式接口参数类型返回类型用途
Consumer 消费型接口Tvoidvoid accept(T t);
Supplier 供给型接口voidTT get();
Function<T, R> 函数型接口TRR apply(T t);
Predicate 断言型接口Tbooleanbooelan test(T t);
BiConsumer<T, U>T,Uvoid对类型为T,U参数应用操作。包含方法为void accept(T t,U u);
BiFunction<T, U, R>T,UR对类型为T,U参数应用操作,并返回R类型的结果。包含方法为R apply(T t,U u);
UnaryOperator extends Function<T, T>TT对类型为T的对象进行一元运算,并返回T类型的结果。包含方法为T apply(T t);
BinaryOperator extends BiFunction<T,T,T>T,TT对类型为T的对象进行二元运算,并返回T类型的结果。包含方法为T apply(T t1,T t2);
ToIntFunction ToLongFunction ToDoubleFunctionTint long double分别计算int、long、double值的函数
IntFunction LongFunction DoubleFunctionint long doubleR参数为int、long、double类型的函数

应用场景:当项目中需要一个接口,并且该接口中只有一个抽象方法,就没必要去创建新的接口,直接选择Java提供的使用合适的函数式接口即可

方法、构造方法和数组引用

方法、构造方法和数组引用就是Lambda的另一种表现形式

方法引用

若Lamdba表达式中的内容由方法已经实现了,可以使用方法引用这个技能

当你需要使用方法引用时,目标引用放在分隔符::前,方法的名称放在后面

对象::实例方法

Lambda表达式中调用方法的参数类型和返回值必须和函数式接口中的抽象方法一致

public class Test1 {@Testpublic void test01() {
//		I1 i1 = (x)->System.out.println(x);
//		i1.method("abcd");//println里的参数列表和返回值类型必须和method方法一致才行PrintStream ps = System.out;I1 i1 = ps::println;//对象::实例方法i1.method("abcd");	}
}
interface I1{public void method(String str);
}

类名::静态方法

Lambda表达式中调用方法的参数类型和返回值必须和函数式接口中的抽象方法一致

public class Test1 {@Testpublic void test01() {
//		Comparator<Integer> com = (x,y)-> Integer.compare(x, y);
//		int compare = com.compare(10, 20);
//		System.out.println(compare);//类名::静态方法Comparator<Integer> com = Integer::compare;int compare = com.compare(10, 20);System.out.println(compare);}}

类名::实例方法

Lambda表达式参数列表中第一个参数必须是实例方法的调用者

Lambda表达式参数列表中第二个参数必须是实例方法的参数

public class Test1 {@Testpublic void test01() {
//		I1<String> i1 = (x,y) -> x.equals(y);
//		boolean method = i1.method("abc", "abc");
//		System.out.println(method);//类名::实例方法//注意:Lambda表达式参数列表中第一个参数是equals方法的调用者,//	   Lambda表达式参数列表中第二个参数是equals方法的参数I1<String> i1 = String::equals;boolean method = i1.method("abc", "abc");System.out.println(method);}
}
interface I1<T>{public boolean method(T t1,T t2);
}
构造方法引用

类名::new

需要调用的构造方法的参数列表必须和函数式接口中抽象方法的参数列表一致

public class Test1 {@Testpublic void test01() {	//需求:创建学生对象I1<Student> i1 = Student::new;
//		System.out.println(i1.method());
//      System.out.println(i1.method("桥本有菜",24));System.out.println(i1.method("桥本有菜",24,8888,Course.JAVA));}
}
interface I1<T>{
//	public T method();public T method(String name,int age,double salary,Course course);
}
enum Course{//课程枚举JAVA,HTML,PYTHON;
}
class Student{//学生类private String name;private int age;private double salary;private Course course;...
}
数组引用

语法格式:type[]::new

public class Test1 {@Testpublic void test01() {	//创建数组I1<String[]> i1 = String[]::new;System.out.println(Arrays.toString(i1.method(10)));}
}
interface I1<T>{public T method(int capacity);
}

Stream

简介

Stream(流)是数据渠道,用于操作数据源(集合、数组等),生成元素序列。换言之,集合是存储数据的容器,流使用操作这些数据的

Stream可以对集合进行非常复杂的查找、过滤、映射数据等操作,类似于SQL执行数据库查询。Stream提供了一种高效且易于使用的处理数据的方式

注意:

  • Stream不会存储数据
  • Stream不会改变源数据,通过一系列操作数据源会返回一个持有结果的新Stream
  • Stream操作是延迟执行的,意味着流会等到需要结果的时候才执行
执行步骤
  1. 创建Stream:通过数据源(集合、数组等)获取一个Stream
  2. 中间操作:中间操作链,对源数据的数据进行处理
  3. 终止操作:执行中间操作,并产生结果
创建Stream
public class Test1 {@Testpublic void test01() {//方式一:通过Collection接口提供的stream()-串行流或parallelStream()-并行流 获取流对象List<String> list = new ArrayList<>();Stream<String> stream1 = list.stream();//方式二:通过Arrays的静态方法stream()获取流对象String[] strs = new String[10];Stream<String> stream2 = Arrays.stream(strs);//方式三:通过Stream的静态方法of()获取流对象Stream<String> stream3 = Stream.of("aaa","bbb","ccc");//方式四:创建无限流//iterate()迭代Stream<Integer> stream4 = Stream.iterate(1, (x)->x+=100);stream4.limit(3).forEach(System.out::println);//方式五:创建无限流Stream<Double> stream5 = Stream.generate(()->Math.random());stream5.limit(3).forEach(System.out::println);}
}

注意:多个中间操作可以连接成一个流水线,除非流水线触发终止操作,否则中间操作不会执行任何的处理,而在终止操作时一次性全部处理,称为惰性求值/延迟加载

中间操作 - 筛选与切片
方法描述
filter(Predicate p)从流中排除元素
limit(long maxSize)设置限制数据条数
skip(long n)跳过元素,返回跳过n个元素的流,若流中不满足n个元素则返回空流。与limit()互补
distinct()筛选,流通过元素对象的hashCode()和equals()方法去除重复元素

如果没有终止操作,中间操作就不会被调用,终止操作时一次性全部处理,这种称为惰性求值/延迟加载

public class Test1 {List<Student> stuList = Arrays.asList(new Student("张三", 28, 4800,Course.JAVA),new Student("李四", 36, 7200,Course.JAVA),new Student("王五", 19, 9600,Course.HTML),new Student("赵六", 42, 6100,Course.HTML),new Student("孙七", 23, 9600,Course.PYTHON),new Student("吴八", 31, 3000,Course.PYTHON),new Student("李四", 36, 7200,Course.JAVA));@Testpublic void test01() {	//需求1:过滤掉小于5000的学生对象Stream<Student> stream = stuList.stream().filter((x)-> {System.out.println("中间操作");return x.getSalary()>5000;});//迭代输出流里的数据就等同于终止操作//迭代功能在forEach()中完成,称为内部迭代(集合使用iterator()称为外部迭代)stream.forEach(System.out::println);}@Testpublic void test02() {	//需求2:过滤掉小于5000的学生对象,并显示3条//注意:因为限制了数据条数,所以满足数据条数后,后续的操作就不再运行了,效率就提高了Stream<Student> stream = stuList.stream().filter((x)-> {System.out.println("短路");return x.getSalary()>5000;}).limit(3);//迭代输出流里的数据就等同于终止操作//迭代功能在forEach()中完成,称为内部迭代(集合使用iterator()称为外部迭代)stream.forEach(System.out::println);}@Testpublic void test03() {	//需求3:过滤掉小于5000的学生对象,并跳过第1个学生对象Stream<Student> stream = stuList.stream().filter((x)-> x.getSalary()>5000).skip(1);//迭代输出流里的数据就等同于终止操作//迭代功能在forEach()中完成,称为内部迭代(集合使用iterator()称为外部迭代)stream.forEach(System.out::println);}@Testpublic void test04() {	//需求4:过滤掉小于5000的学生对象,并筛选掉重复元素//Stream底层通过元素对象(Student对象)的hashCode()和equals()方法去除重复元素Stream<Student> stream = stuList.stream().filter((x)-> x.getSalary()>5000).distinct();//迭代输出流里的数据就等同于终止操作//迭代功能在forEach()中完成,称为内部迭代(集合使用iterator()称为外部迭代)stream.forEach(System.out::println);}
}
enum Course{//课程枚举JAVA,HTML,PYTHON;
}
class Student{//学生类private String name;private int age;private double salary;private Course course;...
}
中间操作 - 映射
方法描述
map(Function<?, ? > mapper)将流中所有元素映射成一个新的元素或者提取信息
flatMap(Function<?, ? extends Stream<? >> mapper)将流中的流整合(整合成平面/平铺流)
public class Test1 {List<String> nameList = Arrays.asList("张三","李四","王五","赵六","孙七","吴八");	List<Student> stuList = Arrays.asList(new Student("张三", 28, 4800,Course.JAVA),new Student("李四", 36, 7200,Course.JAVA),new Student("王五", 19, 9600,Course.HTML),new Student("赵六", 42, 6100,Course.HTML),new Student("孙七", 23, 9600,Course.PYTHON),new Student("吴八", 31, 3000,Course.PYTHON),new Student("李四", 36, 7200,Course.JAVA));@Testpublic void test01() {	//map() - 将流中所有元素映射成一个新的元素 或者 提取信息//方式1:映射成一个新的元素//需求://需求:nameList获取流对象,打印出所有学生的姓氏nameList.stream().map((str)-> str.charAt(0)).forEach(System.out::println);//方式2:映射成提取信息//需求:把原来流中的学生对象替换成学生姓名stuList.stream().map((stu)-> stu.getName()).forEach(System.out::println);}@Testpublic void test02() {	//带着需求学flatMap()//flatMap() - 将流中的流整合(整合成平面/平铺流)//需求:将nameList里的字符串转换为字符输出//解决方案1:使用map()完成需求,可以看到流里包含另外的流,非常麻烦Stream<Stream<Character>> stream = nameList.stream().map(Test1::getCharacterStream);//{{'张','三'},{'李','四'},...}stream.forEach((sm) -> {sm.forEach(System.out::println);});//解决方案2:使用flatMap()完成需求,将流中的流一并整合nameList.stream().flatMap((str)-> getCharacterStream(str)).forEach(System.out::println);//{'张','三'},{'李','四'},...}//将字符串拆分出字符转换为流的方法public static Stream<Character> getCharacterStream(String str){ArrayList<Character> list = new ArrayList<>();for (Character c : str.toCharArray()) {list.add(c);}return list.stream();}
}
enum Course{//课程枚举JAVA,HTML,PYTHON;
}
class Student{//学生类private String name;private int age;private double salary;private Course course;...
}
中间操作 - 排序
方法解释
sorted()使用元素原有排序规则 - Comparable
sorted(Comparator<? super T> comparator)使用自定义排序规则 - Comparator
public class Test1 {List<Student> stuList = Arrays.asList(new Student("张三", 28, 4800,Course.JAVA),new Student("李四", 36, 7200,Course.JAVA),new Student("王五", 19, 9600,Course.HTML),new Student("赵六", 42, 6100,Course.HTML),new Student("孙七", 23, 9600,Course.PYTHON),new Student("吴八", 31, 3000,Course.PYTHON),new Student("吴八", 31, 3000,Course.PYTHON));@Testpublic void test01() {	//使用元素原有排序规则(Comparable<T>)//需求:按照年龄排序stuList.stream().sorted().forEach(System.out::println);}@Testpublic void test02() {	//使用自定义排序规则(Comparator<T>)//需求:按照工资排序stuList.stream().sorted((e1,e2)->{if(e1.getSalary() == e2.getSalary()){return 1;}return (int)(e1.getSalary() - e2.getSalary());}).forEach(System.out::println);	}
}
enum Course{//课程枚举JAVA,HTML,PYTHON;
}
class Student implements Comparable<Student>{//学生类private String name;private int age;private double salary;...
}
终止操作 - 匹配与查找
方法描述
allMatch(Predicate<? super T> predicate)检查是否匹配所有元素
anyMatch(Predicate<? super T> predicate)检查是否匹配至少一个元素
noneMatch(Predicate<? super T> predicate)检查是否没有匹配所有元素
findFirst()返回第一个元素
findAny()返回任意一个元素(但效果不好)
count()返回流中元素的个数
max(Comparator<? super T> comparator)返回流中最大值
min(Comparator<? super T> comparator)返回流中最小值
public class Test1 {List<Student> stuList = Arrays.asList(new Student("张三", 28, 4800,Course.JAVA),new Student("李四", 36, 7200,Course.JAVA),new Student("王五", 19, 9600,Course.HTML),new Student("赵六", 42, 6100,Course.HTML),new Student("孙七", 23, 9600,Course.PYTHON),new Student("吴八", 31, 3000,Course.PYTHON),new Student("吴八", 31, 3000,Course.PYTHON));@Testpublic void test01() {	//需求1:检查流中素所有元素是否匹配 工资>5000boolean allMatch = stuList.stream().allMatch((stu) -> stu.getSalary()>5000);System.out.println(allMatch);//需求2:检查流中素所有元素至少匹配一个 工资>5000boolean  anyMatch = stuList.stream().anyMatch((stu) -> stu.getSalary()>5000);System.out.println(anyMatch);//需求3:检查流中素所有元素是否没有匹配 工资>5000boolean noneMatch = stuList.stream().noneMatch((stu) -> 				stu.getSalary()>5000);System.out.println(noneMatch);//需求4:返回工资最高的学生信息Optional<Student> findFirst = stuList.stream().sorted((stu1,stu2)->Double.compare(stu1.getSalary(),stu2.getSalary())).findFirst();Student stu = findFirst.get();//这种写法防止NullPointerException出现//Student stu = findFirst.orElse(new Student());System.out.println(stu);//需求5:返回随机学生信息(但效果不好)Optional<Student> findAny = stuList.stream().findAny();Student stu = findAny.get();System.out.println(stu);//需求6:获取学生个数long count = stuList.stream().count();System.out.println(count);//需求7:获取最高工资的学生信息Optional<Student> max = stuList.stream().max((stu1,stu2)->Double.compare(stu1.getSalary(),stu2.getSalary()));System.out.println(max.get());//需求8:获取最工资的学生信息Optional<Student> min = stuList.stream().min((stu1,stu2)->Double.compare(stu1.getSalary(),stu2.getSalary()));System.out.println(min.get());}
}
enum Course{//课程枚举JAVA,HTML,PYTHON;
}
class Student implements Comparable<Student>{//学生类private String name;private int age;private double salary;private Course course;...
}
终止操作 - 归约

归约:将流中的元素反复结合起来,得到一个值

map+reduce的连接通常称为map_reduce模式,因Google用它进行网络搜索而出名

方法描述
reduce( T identity , BinaryOperator accumulator)参数:(初始值,结合逻辑)
reduce(BinaryOperator accumulator)参数:(结合逻辑)
public class Test1 {List<Integer> numList = Arrays.asList(1,2,3,4,5,6,7,8,9,10);List<Student> stuList = Arrays.asList(new Student("张三", 28, 4800,Course.JAVA),new Student("李四", 36, 7200,Course.JAVA),new Student("王五", 19, 9600,Course.HTML),new Student("赵六", 42, 6100,Course.HTML),new Student("孙七", 23, 9600,Course.PYTHON),new Student("吴八", 31, 3000,Course.PYTHON),new Student("李四", 36, 7200,Course.JAVA));@Testpublic void test01() {	//需求:获取numList集合中元素的总和Integer reduce = numList.stream().reduce(0, (x,y)->x+y);System.out.println(reduce);}@Testpublic void test02() {	//需求:获取stuList集合中所有学生工资总和Optional<Double> reduce = stuList.stream().map(Student::getSalary).reduce(Double::sum);Double sumSalary = reduce.get();System.out.println(sumSalary);}
}
enum Course{//课程枚举JAVA,HTML,PYTHON;
}
class Student implements Comparable<Student>{//学生类private String name;private int age;private double salary;private Course course;
终止操作 - 收集

收集:将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法

方法描述
collect(Collector<? super T, A, R> collector)把元素放入Collector集合中
public class Test1 {List<Student> stuList = Arrays.asList(new Student("张三", 28, 4800,Course.JAVA),new Student("李四", 36, 7200,Course.JAVA),new Student("王五", 19, 9600,Course.HTML),new Student("赵六", 42, 6100,Course.HTML),new Student("孙七", 23, 9600,Course.PYTHON),new Student("吴八", 31, 3000,Course.PYTHON),new Student("李四", 36, 7200,Course.JAVA));@Testpublic void test01() {//把数据收集到集合中//需求1:把当前学生姓名提取出来,并把数据放入List集合中List<String> list = stuList.stream().map(Student::getName).collect(Collectors.toList());list.forEach(System.out::println);//需求2:把当前学生姓名提取出来,并把数据放入Set集合中Set<String> set = stuList.stream().map(Student::getName).collect(Collectors.toSet());set.forEach(System.out::println);//需求3:把当前学生姓名提取出来,并把数据放入指定集合中HashSet<String> hashSet = stuList.stream().map(Student::getName).collect(Collectors.toCollection(HashSet::new));hashSet.forEach(System.out::println);}	@Testpublic void test02() {//收集流中的各种数据//需求1:收集/获取学生个数Long count = stuList.stream().map(Student::getName).collect(Collectors.counting());System.out.println(count);//需求2:收集/获取学生平均工资Double avg = stuList.stream().collect(Collectors.averagingDouble(Student::getSalary));System.out.println(avg);//需求3:收集/获取学生总工资Double sum = stuList.stream().collect(Collectors.summingDouble(Student::getSalary));System.out.println(sum);//需求4:收集/获取学生工资最大值Optional<Double> max = stuList.stream().map(Student::getSalary).collect(Collectors.maxBy(Double::compareTo));System.out.println(max.get());//需求5:收集/获取学生工资最小值Optional<Double> min = stuList.stream().map(Student::getSalary).collect(Collectors.minBy(Double::compareTo));System.out.println(min.get());//需求6:收集/获取工资最多的学生信息Optional<Student> maxStu = stuList.stream().collect(Collectors.maxBy((stu1,stu2)-> (int)(stu1.getSalary()-stu2.getSalary())));System.out.println(maxStu.get());//需求7:收集/获取工资最少的学生信息Optional<Student> minStu = stuList.stream().collect(Collectors.minBy((stu1,stu2)-> -(int)(stu1.getSalary()-stu2.getSalary())));System.out.println(minStu.get());}	@Testpublic void test03() {//分组//需求:按照学科分组Map<Course, List<Student>> map = stuList.stream().collect(Collectors.groupingBy(Student::getCourse));System.out.println(map);}@Testpublic void test04() {//多级分组//需求:按照学科分组,在按照年龄分组Map<Course, Map<String, List<Student>>> map = stuList.stream().collect(Collectors.groupingBy(Student::getCourse,Collectors.groupingBy((stu)->{if(((Student)stu).getAge() < 28){return "青年";}else if(((Student)stu).getAge() < 40){return "中年";}else{return "老年";}})));System.out.println(map);}@Testpublic void test05() {//分区//需求:按照工资5000为标准分区Map<Boolean, List<Student>> map = stuList.stream().collect(Collectors.partitioningBy((stu) -> stu.getSalary()>5000));System.out.println(map);}@Testpublic void test06() {//获取元素中字段的各种信息//需求:获取学生工资信息,再获取总值、平均值、最大值、最小值DoubleSummaryStatistics collect = stuList.stream().collect(Collectors.summarizingDouble(Student::getSalary));System.out.println(collect.getSum());System.out.println(collect.getAverage());	System.out.println(collect.getMax());System.out.println(collect.getMin());}@Testpublic void test07() {//拼接信息//需求:拼接学生姓名String str1 = stuList.stream().map(Student::getName).collect(Collectors.joining());System.out.println(str1);String str2 = stuList.stream().map(Student::getName).collect(Collectors.joining(","));System.out.println(str2);String str3 = stuList.stream().map(Student::getName).collect(Collectors.joining(",","--","--"));System.out.println(str3);}
}
enum Course{//课程枚举JAVA,HTML,PYTHON;
}
class Student implements Comparable<Student>{//学生类private String name;private int age;private double salary;private Course course;...
}

并行流与串行流

并行流就是把一个内容拆分成多个数据块,并用不同的线程分别处理每个数据块的流。Java8中将并行进行了优化,我们可以很容易的对数据进行并行操作。Stream API可以声明性地通过 parallel() - 并行流 与sequential()-顺序流 之间进行切换。

注意

  1. 默认为顺序流/串行流
  2. 并行流一般在大数据搜索里使用到
  3. JDK1.8之前也有并行流,叫做Fork/Join并行计算框架
public class Test1 {@Testpublic void test01() {//需求:使用并行流计算1-10000000L之和OptionalLong reduce = LongStream.range(0, 10000001L).//生成1-10000000的数流parallel().			//转换为并行流reduce(Long::sum);	//求和System.out.println(reduce);}
}

Optional

Optional类(java. util. Optional)是一个容器类,代表一个存在或不存在的值,原来用null表示一个值不

存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常

此类的设计就是更好的避免空指针异常

方法描述
Optional.of(T t)创建一个Optional实例
Optional.empty()创建一 个空的 Optional实例
Optional.ofNullable(T t)若t不为null,创建Optional实例,否则创建空实例
get()获取Optional实例里的对象
isPresent()判断是否包含值
orElse(T t)如果调用对象包含值, 返回该值,否则返回t
orElseGet(Supplier s)如果调用对象包含值,返回该值,否则返回s获取的值
map(Function f)如果有值对其处理,并返回处理后的Optional,否则返回optional. empty()
flatMap(Function mapper)与map 类似,要求返回值必须是Optional
public class Test1 {@Testpublic void test01() {//创建一个Optional实例,把对象封装到Optional容器里
//		Optional<Student> op = Optional.of(
//          new Student("aaa", 26, 6666, Course.HTML));//创建一个空的Optional容器
//		Optional<Student> op = Optional.empty();//创建一个Optional实例,若对象为null->创建空实例,若对象为不为null->创建Optional实例Optional<Student> op = Optional.ofNullable(new Student("bbb", 26, 7777, Course.PYTHON));//判断容器里是否包含对象if(op.isPresent()){//包含System.out.println("获取容器里的对象:" + op.get().getName());}else{//不包含System.out.println("容器里的对象为null");}//如果容器里有对象就返回,否则就返回新对象Student stu = op.orElse(new Student("ccc", 26, 8888, Course.JAVA));System.out.println(stu.getName());//不同情况下可以返回不同对象,orElseGet()比orElse()可变性更强boolean bool = true;stu = op.orElseGet(()->{if(bool){return new Student("吴彦祖", 26, 8888, Course.JAVA);}else{return new Student("麻生希", 26, 8888, Course.JAVA);}});//获取原容器中的某个值并返回新容器中//map(Function<? super T, ? extends U> mapper)Optional<String> map = op.map(Student::getName);System.out.println(map.get());//与map 类似,要求返回值必须是Optional//flatMap(Function<? super T, Optional<U>> mapper)Optional<String> flatMap = op.flatMap((e)->Optional.of(e.getName()));System.out.println(flatMap.get());}
}
enum Course{//课程枚举JAVA,HTML,PYTHON;
}
class Student implements Comparable<Student>{//学生类private String name;private int age;private double salary;private Course course;...
}

接口的默认方法与静态方法

从JDK1.8开始,接口中可以有默认方法,既default修饰的方法,此方法可以让接口的实现类所调用,而接

口中的静态方法直接用接口名调用即可

public class Test1 {@Testpublic void test01() {MyClass myClass = new MyClass();myClass.defaultMethod();I1.staticMethod();}
}
interface I1{default void defaultMethod(){System.out.println("接口中的默认方法");}public static void staticMethod(){System.out.println("接口中的静态方法");}
}
class MyClass implements I1{}

接口默认方法的”类优先”原则:

  • 如果一个接口中定义了一个默认方法,而接口实现类的父类定义了一个同名的方法时,选择父类中的方法

  • 接口冲突:如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突

public class Test1 {@Testpublic void test01() {MyClass myClass = new MyClass();MyClass.method();}
}
interface I1{default void method(){System.out.println("I1接口中的默认方法");}
}
class Father {public void method(){System.out.println("Father类中的默认方法");}
}
class MyClass extends Father implements I1 {}
public class Test1 {@Testpublic void test01() {MyClass myClass = new MyClass();myClass.method();}
}
interface I1{default void method(){System.out.println("I1接口中的默认方法");}
}
interface I2{default void method(){System.out.println("I2接口中的默认方法");}
}
class MyClass implements I1,I2 {@Overridepublic void method() {//I1.super.method();I2.super.method();}
}

日期组件

JDK1.8提供的新日期类都是不可变的,既不管怎么样的改变,都会产生一个新的实例,他们都是线程安全的

日期组件遵循与IOS-8601世界时间标准

组件简介
包路径类名描述
java.time针对日期和时间操作的包
LocalDate用于表示日期的类
LocalTime用于表示时间的类
LocalDateTime用于表示日期时间的类
Instant时间戳类(1970.1.1 0:0:0 到线程的毫秒数)
Period两个日期间隔类
Duration两个时间间隔类
java.time.chrono针对日期时间特殊格式操作的包
JapaneseChronology日本帝国历法系统类
ThaiBuddhistChronology泰国佛教日历系统类
java.time.format针对时间日期时间格式化操作的包
DateTimeFormatter格式化日期时间类
java.time.temporal针对时间矫正操作的包
java.time.zone针对时区操作的包
日期时间类、时间戳、间隔类
public class Test1 {@Testpublic void test01() {//LocalDate LocalTime LocalDateTime//这三个日期类的使用大致一样//获取当前日期时间对象LocalDateTime ldt1 = LocalDateTime.now();System.out.println(ldt1);//获取指定日期时间对象LocalDateTime ldt2 = LocalDateTime.of(2020, 1, 23, 8, 30, 10, 10);System.out.println(ldt2);//获取ldt1推后的时间日期对象LocalDateTime ldt3 = ldt1.plusYears(2);System.out.println(ldt3);//获取ldt1提前的时间日期对象LocalDateTime ldt4 = ldt3.minusMonths(2);System.out.println(ldt4.getYear());System.out.println(ldt4.getMonthValue());System.out.println(ldt4.getDayOfMonth());System.out.println(ldt4.getHour());System.out.println(ldt4.getMinute());System.out.println(ldt4.getSecond());}@Testpublic void test02() {//使用时间戳(从1970年1月1日0:0:0到现在的毫秒值)//默认创建UTC(世界标准时间)时区的时间戳对象Instant now1 = Instant.now();System.out.println(now1);//获取偏移8小时的偏移日期时间对象OffsetDateTime odt = now1.atOffset(ZoneOffset.ofHours(8));System.out.println(odt);//获取时间戳的毫秒值形式System.out.println(now1.toEpochMilli());//获取一个1970年1月1日0:0:0 往后退1秒的时间戳对象Instant now2 = Instant.ofEpochSecond(1);System.out.println(now2);}@Testpublic void test03() throws InterruptedException {//Duration:时间间隔类Instant now1 = Instant.now();Thread.sleep(1000);Instant now2 = Instant.now();//获取时间间隔类对象Duration duration1 = Duration.between(now1, now2);System.out.println(duration1.toMillis());System.out.println("-----------------------------");LocalTime lt1 = LocalTime.now();Thread.sleep(1000);LocalTime lt2 = LocalTime.now();//获取时间间隔类对象Duration duration2 = Duration.between(lt1, lt2);System.out.println(duration2.toMillis());}@Testpublic void test04() throws InterruptedException {//Period:日期间隔类LocalDate ld1 = LocalDate.now();Thread.sleep(1000);LocalDate ld2 = LocalDate.of(2020, 12, 31);Period period = Period.between(ld1, ld2);System.out.println(period.getYears());System.out.println(period.getMonths());System.out.println(period.getDays());}
}
日期时间格式化类-DateTimeFormatter
public class Test1 {@Testpublic void test01() {//格式化日期时间类LocalDateTime ldt1 = LocalDateTime.now();//获取本地标准的日期时间格式化对象DateTimeFormatter dtf1 = DateTimeFormatter.ISO_LOCAL_DATE_TIME;String strDateTime1 = ldt1.format(dtf1);//格式化时间日期System.out.println(strDateTime1);//自定义日期时间格式化对象DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");String strDateTime2 = ldt1.format(dtf2);//格式化时间日期System.out.println(strDateTime2);//将指定格式的字符串解析成LocalDateTime对象LocalDateTime parse = LocalDateTime.parse("2020年03月12日 11:04:14", dtf2);System.out.println(parse);}
}
时间矫正器类-TemporalAdjuster
public class Test1 {@Testpublic void test01() {//时间矫正器LocalDateTime ldt1 = LocalDateTime.now();//设置指定月份LocalDateTime ldt2 = ldt1.withMonth(10);System.out.println(ldt2);//设置下一个周末LocalDateTime ldt3 = ldt1.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));System.out.println(ldt3);//自定义时间矫正器:设置下一个工作LocalDateTime ldt4 = ldt1.with((temporal)->{LocalDateTime ldt = (LocalDateTime) temporal;DayOfWeek week = ldt.getDayOfWeek();if(week.equals(DayOfWeek.FRIDAY)){//周五return ldt.plusDays(3);}else if(week.equals(DayOfWeek.SATURDAY)){//周六return ldt.plusDays(2);}else{return ldt.plusDays(1);}});System.out.println(ldt4);}
}
时区类
public class Test1 {@Testpublic void test01() {//时区类 //获取所有时区字符串Set<String> set = ZoneId.getAvailableZoneIds();for (String str : set) {System.out.println(str);}//获取指定时区的日期时间对象LocalDateTime ldt1 = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));System.out.println(ldt1);//获取指定时区的日期时间对象 + 偏移量LocalDateTime ldt2 = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));ZonedDateTime zonedDateTime = ldt2.atZone(ZoneId.of("Asia/Tokyo"));System.out.println(zonedDateTime);}
}

重复注解及类型注解

jdk1.8开始可以重复注解

ps:一个类可有多个同样的注解

import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_PARAMETER;import java.lang.annotation.Annotation;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;import org.junit.Test;//重复注解
@Author(name="何老师")
@Author(name="苍老师")
public class Test1 {@Testpublic void test01() throws Exception{//需求1:获取Test1的多个作者注解Class<Test1> ct = Test1.class;Author[] as = ct.getAnnotationsByType(Author.class);for (Author a : as) {System.out.println(a.name());}//需求2:获取method方法中参数里的注解Method m = ct.getMethod("method", String.class);Annotation[][] parameterAnnotations = m.getParameterAnnotations();//获取参数中注解列表(有可能一个参数多个注解)for (Annotation[] annotations : parameterAnnotations) {for (Annotation an : annotations) {//获取具体注解System.out.println(an);}} }public static void method(@Author(name="波老师") String str){}
} //作者注解的容器
@Target(TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Authors{Author[] value();
}
//作者注解
@Repeatable(Authors.class)
@Target({TYPE, PARAMETER,TYPE_PARAMETER})//TYPE_PARAMETER-类型注解:作用在参数
@Retention(RetentionPolicy.RUNTIME)
@interface Author{String name();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/17353.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

openssh升级

原因&#xff1a;因为低版本出现了漏洞 过程&#xff1a; 此时&#xff0c;root不能登录。 修改/etc/pam.d/login 第2行前面加上#&#xff0c;保存退出 /etc/pam.d/remote 第2行前面加上#&#xff0c;保存退出 此时root可以通过telnet登录了 二、升级openssl和openssh 【L…

C++容器之栈(std::stack)

目录 1 概述2 使用实例3 接口使用3.1 construct3.2 empty3.3 size3.4 top3.5 push3.6 emplace3.7 pop3.8 swap1 概述 堆栈是一种容器适配器,专门设计用于在后进先出(后进先出)环境中操作,其中元素仅从容器的一端插入和提取。   堆栈被实现为容器适配器,容器适配器是使用…

下半年开考,仅考1次,系统集成项目管理工程师考试安排!

《系统集成项目管理工程师教程》第3版官方教材将在下半年开始使用&#xff0c;相对于之前的版本&#xff0c;变化很大。新老考生都需要重新学习。历年真题显示&#xff0c;官方教材非常重要&#xff0c;考试题目大部分都可以在教材中找到原文。因此&#xff0c;对于下半年的考试…

Go 实现 WebSocket 的双向通信

在Go语言中实现WebSocket的双向通信通常需要使用第三方库&#xff0c;其中 gorilla/websocket 是一个非常流行和广泛使用的库。 1、安装 go get github.com/gorilla/websocket 2、编写WebSocket服务器代码 package mainimport ("fmt""github.com/gorilla/we…

【C++】构造函数、析构函数、拷贝构造与运算符重载

文章目录 1.类的六个默认构造函数2.构造函数2.1特性2.1.1 函数名与类名相同2.1.2. 无返回值&#xff08;不能写void&#xff09;2.1.3. 对象实例化时编译器自动调用对应的构造函数2.1.4 构造函数可以重载2.1.5编译器生成默认的构造函数2.1.6编译器生成的默认构造有何用&#xf…

linux开发之设备树写法

设备树的根节点 设备树子节点和子子节点,子节点在根节点范围内 包含子节点以及子子节点 节点名称 比如这里led就是这个gpio的小名,可以直接用 gpio22020101是这里的名字,也就是要用这个gpio,符号后面的一串数字使用了这个gpio的寄存器地址,因为可能会用很多gpio,所以加入寄存…

游戏开发与软件开发的区别

游戏开发和软件开发作为两个重要的领域&#xff0c;分别吸引了大量的开发者和用户。尽管这两者在许多方面存在共通之处&#xff0c;但它们在目标、开发过程、技术需求和团队结构上都有显著的区别。本文将详细探讨游戏开发与软件开发的不同之处。 目标与用户体验 游戏开发的主…

如何测试大型语言模型

围绕使用AI助手来减少手动工作、通过代码生成器提高软件开发者的生产力&#xff0c;以及利用生成式AI进行创新&#xff0c;这些话题一直为公众所热议。同时&#xff0c;商业机会正推动许多开发团队构建知识库、使用向量数据库&#xff0c;并在其应用中嵌入大型语言模型&#xf…

console.log——NPM库

前期回顾 Vue3 TS 项目实战 - 后台管理系统 - 按钮权限_vue3ts后台管理-CSDN博客 目录 &#x1f6a9;不使用NPM插件的方式 第一步&#xff1a;创建log函数-源码 第二步&#xff1a;注册到window上 第三步&#xff1a;扩展Window接口 第四步&#xff1a;确保类型文件…

CMake是怎么找到Qt相关模块的

当我们使用QT创建了一个CMake项目后&#xff0c;我们尝试使用CMake编译时&#xff0c;会遇到找不到Qt的模块的问题&#xff0c; find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets WebSockets WebEngineWidgets) 复制代码 深入了解find_package之后&#xff0c;我们就…

南卡、韶音、Cleer开放式耳机如何选?全面对比测评拒绝智商税!

随着开放式耳机在生活中日益流行&#xff0c;市场上的多样化选择有时也伴随着质量参差不齐的问题&#xff0c;部分产品因成本控制而牺牲了材质和音质&#xff0c;给消费者在寻找高质量耳机时增添了困扰。 作为一名耳机评测领域的从业者&#xff0c;近期我投入大量精力对多款开…

Softing线上研讨会 | 使用Softing smartLink SW-HT将AB PLC下的HART设备连接到艾默生AMS设备管理器

| (免费) 线上研讨会时间&#xff1a;2024年6月25日 14:00~14:45 / 22:30~23:15 艾默生AMS设备管理器凭借其全面功能、优秀诊断能力、兼容性以及远程监控和管理功能&#xff0c;在过程工业中被证明是一款先进的工厂资产管理工具&#xff0c;可用于设备配置、诊断和监控、仪表校…

2023年信息素养大赛小学组C++智能算法复赛真题

今天给大家分享2023年全国青少年信息素养大赛小学组C智能算法挑战赛复赛里面的一套真题&#xff0c;希望有助于大家了解复赛的难度及备考。 其他真题下载&#xff1a;网盘-真题-信息素养大赛

富格林:阻挠欺诈套路需要明辨

富格林认为&#xff0c;现货交易平台的重要性对投资者们来说众所周知&#xff0c;但操作的软件也同样重要。投资者在选好平台后&#xff0c;还需要下载软件来进行交易。富格林提醒&#xff0c;正规操作可以阻挠欺诈被骗&#xff0c;投资者应慎重选择操作软件。下面富格林将给投…

MongoDB 原子操作:确保数据一致性和完整性的关键

在 MongoDB 中&#xff0c;原子操作是指可以一次性、不可分割地执行的数据库操作。这些操作能够保证在多个并发操作中不会出现数据不一致或者丢失的情况&#xff0c;确保数据库的数据完整性和一致性。 基本语法 MongoDB 的原子操作通常与更新操作相关&#xff0c;其基本语法如…

clocking wizard IP核通过AXI4-Lite接口实现动态重新配置应用实例

在最近的FPGA应用中&#xff0c;应用到了基于Zynq 7000的Uart串口设计&#xff0c;为了让串口的时钟更精确&#xff0c;采用了外部时钟模式&#xff0c;如下图所示。外部时钟连接到了Clocking Wizard IP核的输出端。 在串口通信时&#xff0c;发现串口有错码出现。例如&#xf…

triton之paged attention

一 原理 图解大模型计算加速系列之&#xff1a;vLLM核心技术PagedAttention原理 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/691038809 二 源码分析 1 测试参数设置 test_paged_attention(num_seqs32,num_heads(64, 64),head_size64,block_size16,dtypetorch.float16,…

C语言知识大纲

一、基础 (一)变量定义和使用 (二)数据类型的字节数 (三)变量转换 (四)程序主要结构 (五)if和else判断 (六)switch判断 (七)while循环 (八)do while循环 (九)for循环 (十)基本输入输出 (十一)数组定义和使用 (十二)函数定义和使用 (十三)指针 (十四)多级指针 (十…

奇门遁甲古籍1《奇门秘术》(双页版)PDF电子书

《奇门秘术》 全书共102页 时间有限&#xff0c;仅上传部分图片&#xff0c;结缘私&#xff01;

数据结构—队列(C语言实现)

文章目录 前言一、队列的概念二、队列的实现Queue.hQueue.c 三、设计循环队列问题数组实现链表实现 总结 前言 嗨喽喽&#xff01;&#xff01;小伙伴们&#xff0c;大家好哇&#xff0c;欢迎来到我的博客&#xff01; 今天将要分享的是另一种数据结构—队列&#xff0c;以及…