修改时间:2021年1月12日
作者:pp_x
邮箱:pp_x12138@163.com
文章目录
- Java8新特性
- Java8概述
- 函数式接口
- lambda表达式
- 方法引用
- Stream接口
- 基本概念
- 使用步骤
- 创建方式
- 中间操作
- 映射
- 排序
- 终止操作
- optional类
- 基本概念
- Java9新特性
- Java9的概述
- 模块化的使用
- 模块化的优势
- 钻石操作符的使用升级
- 集合工厂方法
- 基本概念
- 实际意义
- InputStream的增强
- Java10新特性
- Java10概述
- 局部变量的推断
- 基本概念
- 实际意义
- Java11新特性
- Java11概述
- 简化的编译操作
- String新增的方法
Java8新特性
Java8概述
- Java8是 Java 语言的一个重要版本,该版本于2014年3月发布,是自Java5以来最具革命性的版本,这个版本包含语言、编译器、库、工具和JVM等方面的十多个新特性。
函数式接口
- 函数式接口主要指只包含一个抽象方法的接口,如:
java.lang.Runnable
、java.util.Comparator
接口等。 - Java8提供
@FunctionalInterface注解
来定义函数式接口,若定义的接口不符合函数式的规范便会报错。
接口名称 | 方法声明 | 功能介绍 |
Consumer | void accept(T t) | 根据指定的参数执行操作 |
Supplier | T get() | 得到一个返回值 |
Function<T,R> | R apply(T t) | 根据指定的参数执行操作并返回 |
Predicate | boolean test(T t) | 判断指定的参数是否满足条件 |
lambda表达式
- Lambda 表达式是实例化函数式接口的重要方式,使用 Lambda 表达式可以使代码变的更加简洁紧凑。
- lambda表达式:参数列表、箭头符号->和方法体组成,而方法体中可以是表达式,也可以是语句块。
- 语法格式:
(参数列表) -> { 方法体; }
- 其中()、参数类型、{} 以及return关键字 可以省略。
方法引用
- 方法引用主要指通过方法的名字来指向一个方法而不需要为方法引用提供方法体,该方法的调用交给函数式接口执行。
- 方法引用使用一对冒号 :: 将类或对象与方法名进行连接,通常使用方式如下:
- 对象的非静态方法引用
ObjectName :: MethodName
- 类的静态方法引用
ClassName :: StaticMethodName
- 类的非静态方法引用
ClassName :: MethodName
- 构造器的引用
ClassName :: new
- 数组的引用
TypeName[] :: new
- 方法引用是在特定场景下lambda表达式的一种简化表示,可以进一步简化代码的编写使代码更加紧凑简洁,从而减少冗余代码。
函数式接口
package com.lagou.newproperties;
import java.util.Comparator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
public class FunctionalInterfaceTest {
public static void main(String[] args) {
// 1.匿名内部类的语法格式: 父类/接口类型 引用变量名 = new 父类/接口类型(){ 方法的重写 };
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("我是既没有参数又没有返回值的方法!");
}
};
runnable.run(); // 我是既没有参数又没有返回值的方法!
// 使用lambda表达式实现函数式接口对象的创建: (参数列表)->{方法体;}
//Runnable runnable1 = () -> { System.out.println("我是既没有参数又没有返回值的方法!"); };
Runnable runnable1 = () -> System.out.println("我是既没有参数又没有返回值的方法!");
runnable1.run();
System.out.println("----------------------------------------------------------------------");
Consumer consumer = new Consumer() {
@Override
public void accept(Object o) {
System.out.println(o + "有参但没有返回值的方法就是我!");
}
};
consumer.accept("友情提示:"); // 友情提示:有参但没有返回值的方法就是我!
//Consumer consumer1 = (Object o) -> {System.out.println(o + "有参但没有返回值的方法就是我!");};
//Consumer consumer1 = (o) -> System.out.println(o + "有参但没有返回值的方法就是我!");
// 省略了()、参数类型、{}, 自动类型推断
Consumer consumer1 = o -> System.out.println(o + "有参但没有返回值的方法就是我!");
consumer1.accept("友情提示:");
System.out.println("----------------------------------------------------------------------");
Supplier supplier = new Supplier() {
@Override
public Object get() {
return "无参有返回值!";
}
};
System.out.println(supplier.get()); // 无参有返回值
//Supplier supplier1 = () -> {return "无参有返回值!";};
Supplier supplier1 = () -> "无参有返回值!";
System.out.println(supplier1.get());
System.out.println("----------------------------------------------------------------------");
Function function = new Function() {
@Override
public Object apply(Object o) {
return o;
}
};
System.out.println(function.apply("有参有返回值的方法")); // 有参有返回值的方法
// return 和 {} 都可以省略
Function function1 = o -> o;
System.out.println(function1.apply("有参有返回值的方法"));
System.out.println("----------------------------------------------------------------------");
Comparator comparator = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return 0;
}
};
System.out.println(comparator.compare(10, 20)); // 0
Comparator comparator1 = (o1, o2) -> 0;
System.out.println(comparator1.compare(10, 20));
System.out.println("----------------------------------------------------------------------");
Predicate predicate = new Predicate() {
@Override
public boolean test(Object o) {
return false;
}
};
System.out.println(predicate.test("hello")); // false
Predicate predicate1 = o -> false;
System.out.println(predicate1.test("hello"));
}
}
方法引用
package com.lagou.newproperties;
import java.util.Arrays;
import java.util.Comparator;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
public class MethodReferenceTest {
public static void main(String[] args) {
// 1.使用匿名内部类的方式通过函数式接口Runnable中的方法实现对Person类中show方法的调用
Person person = new Person("zhangfei", 30);
Runnable runnable = new Runnable() {
@Override
public void run() {
person.show();
}
};
runnable.run(); // 没事出来秀一下哦
System.out.println("-------------------------------------------------------------");
// 2.使用lambda表达式的方式实现Person类中show方法的调用
Runnable runnable1 = () -> person.show();
runnable1.run(); // 没事出来秀一下哦
System.out.println("-------------------------------------------------------------");
// 3.使用方法引用的方式实现Person类中show方法的调用
Runnable runnable2 = person::show;
runnable2.run();
System.out.println("-------------------------------------------------------------");
// 4.使用匿名内部类的方式通过函数式接口Consumer中的方法来实现Person类中setName方法的调用
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
person.setName(s);
}
};
consumer.accept("guanyu");
System.out.println("person = " + person); // guanyu 30
System.out.println("-------------------------------------------------------------");
// 5.使用lambda表达式的方式实现Person类中setName方法的调用
Consumer<String> consumer1 = s -> person.setName(s);
consumer1.accept("liubei");
System.out.println("person = " + person); // liubei 30
System.out.println("-------------------------------------------------------------");
// 6.使用方法引用的方式实现Person类中setName方法的调用
Consumer<String> consumer2 = person::setName;
consumer2.accept("zhangfei");
System.out.println("person = " + person); // zhangfei 30
System.out.println("-------------------------------------------------------------");
// 7.使用匿名内部类的方式通过函数式接口Supplier中的方法来实现Person类中getName方法的调用
Supplier<String> supplier = new Supplier<String>() {
@Override
public String get() {
return person.getName();
}
};
System.out.println(supplier.get()); // zhangfei
Supplier<String> supplier1 = () -> person.getName();
System.out.println(supplier1.get()); // zhangfei
Supplier<String> supplier2 = person::getName;
System.out.println(supplier2.get()); // zhangfei
System.out.println("-------------------------------------------------------------");
// 8.使用匿名内部类的方式通过函数式接口Function中的方法实现Integer类中parseInt方法的调用
Function<String, Integer> function = new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
};
System.out.println(function.apply("12345")); // 12345
Function<String, Integer> function1 = s -> Integer.parseInt(s);
System.out.println(function1.apply("12345")); // 12345
Function<String, Integer> function2 = Integer::parseInt;
System.out.println(function2.apply("12345")); // 12345
System.out.println("-------------------------------------------------------------");
// 9.使用匿名内部类的方式通过函数式接口Comparator中的方法实现Integer类中compare方法的调用
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
System.out.println(comparator.compare(10, 20)); // -1
Comparator<Integer> comparator1 = (o1, o2) -> Integer.compare(o1, o2);
System.out.println(comparator1.compare(10, 20)); // -1
Comparator<Integer> comparator2 = Integer::compare;
System.out.println(comparator2.compare(10, 20)); // -1
System.out.println("-------------------------------------------------------------");
// 10.使用匿名内部类的方式通过类名来调用非静态方法
// 其中一个参数对象作为调用对象来调用方法时,可以使用上述方式 更抽象
Comparator<Integer> comparator3 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
};
System.out.println(comparator3.compare(10, 20)); // -1
Comparator<Integer> comparator4 = (o1, o2) -> o1.compareTo(o2);
System.out.println(comparator4.compare(10, 20)); // -1
Comparator<Integer> comparator5 = Integer::compareTo;
System.out.println(comparator5.compare(10, 20)); // -1
System.out.println("-------------------------------------------------------------");
// 11.使用匿名内部类的方式通过Supplier函数式接口创建Person类型的对象并返回
Supplier<Person> supplier3 = new Supplier<Person>() {
@Override
public Person get() {
return new Person();
}
};
System.out.println(supplier3.get()); // null 0
Supplier<Person> supplier4 = () -> new Person();
System.out.println(supplier4.get()); // null 0
Supplier<Person> supplier5 = Person::new;
System.out.println(supplier5.get()); // null 0
System.out.println("-------------------------------------------------------------");
// 12.使用匿名内部类的方式通过BiFunction函数式接口采用有参方式创建Person类型的对象并返回
BiFunction<String, Integer, Person> biFunction = new BiFunction<String, Integer, Person>() {
@Override
public Person apply(String s, Integer integer) {
return new Person(s, integer);
}
};
System.out.println(biFunction.apply("zhangfei", 30)); // zhangfei 30
BiFunction<String, Integer, Person> biFunction1 = (s, integer) -> new Person(s, integer);
System.out.println(biFunction1.apply("zhangfei", 30)); // zhangfei 30
BiFunction<String, Integer, Person> biFunction2 = Person::new;
System.out.println(biFunction2.apply("zhangfei", 30)); // zhangfei 30
System.out.println("-------------------------------------------------------------");
// 12.使用匿名内部类的方式通过Function函数式接口创建指定数量的Person类型的对象数组并返回
Function<Integer, Person[]> function3 = new Function<Integer, Person[]>() {
@Override
public Person[] apply(Integer integer) {
return new Person[integer];
}
};
Person[] pArr = function3.apply(3);
System.out.println(Arrays.toString(pArr));
Function<Integer, Person[]> function4 = integer -> new Person[integer];
System.out.println(Arrays.toString(function4.apply(4)));
Function<Integer, Person[]> function5 = Person[]::new;
System.out.println(Arrays.toString(function5.apply(5)));
}
}
Stream接口
基本概念
-
java.util.stream.Stream
接口是对集合功能的增强,可以对集合元素进行复杂的查找、过滤、筛选等操作。 - Stream接口借助于Lambda 表达式极大的提高编程效率和程序可读性,同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势。
使用步骤
- 创建Stream,通过一个数据源获取一个流
- 转换Stream,每次返回获得一个新的Stream对象
- 对Stream进行聚合操作并产生结果
创建方式
- 方式一:通过调用集合的默认方法来获取流,如:
default Stream stream()
- 方式二:通过数组工具类中的静态方法来获取流,如:
static IntStream stream(int[] array)
- 方式三:通过Stream接口的静态方法来获取流,如:
static Stream of(T... values)
- 方式四:通过Stream接口的静态方法来获取流,
static Stream generate(Supplier<? extends T> s)
中间操作
方法声明 | 功能介绍 |
Stream filter(Predicate<? super T> predicate) | 返回一个包含匹配元素的流 |
Stream distinct() | 返回不包含重复元素的流 |
Stream limit(long maxSize) | 返回不超过给定元素数量的流 |
Stream skip(long n) | 返回丢弃前n个元素后的流 |
// .将List集合中所有成年人过滤出来并放入另外一个集合中打印
list.stream().filter(new Predicate<Person>() {
@Override
public boolean test(Person person) {
return person.getAge() >= 18;
}
}).forEach(new Consumer<Person>() {
@Override
public void accept(Person person) {
System.out.println(person);
}
});
System.out.println("-------------------------------------------------------");
// 4.使用lambda表达式对上述代码进行优化
//list.stream().filter(person -> person.getAge() >= 18).forEach(person -> System.out.println(person));
list.stream().filter(person -> person.getAge() >= 18).forEach(System.out::println);
// 5.实现对集合中元素通过流跳过2个元素后再取3个元素后打印
list.stream().skip(2).limit(3).forEach(System.out::println);
映射
方法声明 | 功能 |
Stream map(Function<? super T,? extends R> mapper) | 返回每个处理过元素组成的流 |
Stream flatMap(Function<? super T,? extends Stream<? extends R>> mapper) | 返回每个被替换过元素组成的流,并将所有流合成一个流 |
// 6.实现集合中所有元素中的年龄获取出来并打印
list.stream().map(new Function<Person, Integer>() {
@Override
public Integer apply(Person person) {
return person.getAge();
}
}).forEach(System.out::println);
//list.stream().map(person -> person.getAge()).forEach(System.out::println);
list.stream().map(Person::getAge).forEach(System.out::println);
排序
方法声明 | 功能 |
Stream sorted() | 返回经过自然排序后元素组成的流 |
Stream sorted(Comparator<? super T> comparator) | 返回经过比较器排序后元素组成的流 |
list.stream().sorted().forEach(System.out::println);
终止操作
- 匹配与查找
方法声明 | 功能介绍 |
Optional findFirst() | 返回该流的第一个元素 |
boolean allMatch(Predicate<? super T> predicate) | 返回所有元素是否匹配 |
boolean noneMatch(Predicate<? super T> predicate) | 返回没有元素是否匹配 |
Optional max(Comparator<? super T> comparator) | 根据比较器返回最大元素 |
Optional min(Comparator<? super T> comparator) | 根据比较器返回最小元素 |
long count() | 返回元素的个数 |
void forEach(Consumer<? super T> action) | 对流中每个元素执行操作 |
// 8.判断集合中是否没有元素的年龄是大于45岁的
System.out.println("------------------------判断集合中是否没有元素的年龄是大于45岁的-------------------------------");
boolean b1 = list.stream().noneMatch(new Predicate<Person>() {
@Override
public boolean test(Person person) {
return person.getAge() > 45;
}
});
System.out.println(b1);
boolean b2 = list.stream().noneMatch(person -> person.getAge() > 45);
System.out.println(b2);
//9、按照指定的比较器规则回去所有元素中的最大值
System.out.println("------------------------按照指定的比较器规则回去所有元素中的最大值-------------------------------");
Optional<Person> max = list.stream().max(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge();
}
});
System.out.println(max);
max = list.stream().max(Person::compareTo);
System.out.println(max);
- 规约
方法声明 | 功能 |
Optional reduce(BinaryOperator accumulator) | 返回结合后的元素值 |
//10、实现将集合中所有元素的年龄映射出来
System.out.println("------------------------实现将集合中所有元素的年龄映射出来-------------------------------");
Optional<Integer> reduce = list.stream().map(Person::getAge).reduce(new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer integer, Integer integer2) {
return integer + integer2;
}
});
System.out.println("年龄的累加和是:"+reduce);
Optional<Integer> reduce1 = list.stream().map(Person::getAge).reduce(((integer, integer2) -> integer + integer2));
Optional<Integer> reduce2 = list.stream().map(Person::getAge).reduce(Integer::sum);
System.out.println("年龄的累加和是:"+reduce1);
System.out.println("年龄的累加和是:"+reduce2);
- 收集
方法声明 | 功能介绍 |
<R,A> R collect(Collector<? super T,A,R> collector) | 使用收集器对元素进行处理 |
// 11.实现将集合中所有元素的姓名映射出来并收集到集合中打印
list.stream().map(Person::getName).collect(Collectors.toList()).forEach(System.out::println);
optional类
基本概念
-
java.util.Optional
类可以理解为一个简单的容器,其值可能是null或者不是null,代表一个值存在或不存在。 - 该类的引入很好的解决空指针异常,不用显式进行空值检测
方法声明 | 功能介绍 |
static Optional ofNullable(T value) | 根据参数指定数值来得到Optional类型的对象 |
Optional map(Function<? super T,? extends U> mapper) | 根据参数指定规则的结果来得到Optional类型的对象 |
T orElse(T other) | 若该值存在就返回,否则返回other的数值。 |
public class OptionalTest {
public static void main(String[] args) {
//String str1 = "hello";
String str1 = null;
if (null != str1) {
System.out.println("字符串的长度是:" + str1.length()); // 5 空指针异常
} else {
System.out.println("字符串为空,因此长度为0!");
}
// Java8中使用Optional类实现空值的处理
// 1.将数据str1装到Optional对象代表的容器中
Optional<String> optional = Optional.ofNullable(str1);
// 2.建立映射关系 使用字符串的长度与字符串建立映射关系
/*Optional<Integer> integer = optional.map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return s.length();
}
});*/
//Optional<Integer> integer = optional.map(s -> s.length());
Optional<Integer> integer = optional.map(String::length);
// 3.若字符串为空则打印0,否则打印字符串的数值
System.out.println("integer = " + integer); // Optional.empty
System.out.println(integer.orElse(0)); // 0 调用orElse的引用若为空,则返回参数0 否则返回引用
}
}
Java9新特性
Java9的概述
- Java9发布于2017年9月发布,带来了很多新特性,其中最主要的变化是模块化系统。
- 模块就是代码和数据的封装体,模块的代码被组织成多个包,每个包中包含Java类和接口,模块的数据则包括资源文件和其他静态信息。
模块化的使用
- 在 module-info.java 文件中,我们可以用新的关键词module来声明一个模块,具体如下:
module 模块名称 {}
模块化的优势
- 减少内存的开销。
- 可简化各种类库和大型应用的 开发和维护。
- 安全性,可维护性,提高性能。
钻石操作符的使用升级
- 在Java9中允许在匿名内部类的使用中使用钻石操作符。
集合工厂方法
基本概念
- Java9的List、Set和Map集合中增加了静态工厂方法of实现不可变实例的创建。
- 不可变体现在无法添加、修改和删除它们的元素。
- 不允许添加null元素对象。
public class CollectionTest {
public static void main(String[] args) {
// 创建List类型的不可变实例
List<Integer> list = List.of(1, 2, 3, 4, 5);
//list.add(6); // 编译ok,运行发生UnsupportedOperationException不支持此操作的异常
System.out.println(list); // [1, 2, 3, 4, 5]
Set<Integer> set = Set.of(6, 7, 8);
//set.add(null);// 编译ok,运行发生UnsupportedOperationException不支持此操作的异常
Map<Integer, String> map = Map.of(1, "one", 2, "two");
//map.put(3, "three");// 编译ok,运行发生UnsupportedOperationException不支持此操作的异常
}
}
实际意义
- 保证线程安全:在并发程序中既保证线程安全性,也大大增强了并发时的效率。
- 被不可信的类库使用时会很安全。
- 如果一个对象不需要支持修改操作,将会节省空间和时间的开销。
- 可以当作一个常量来对待,并且这个对象在以后也不会被改变。
InputStream的增强
- InputStream类中提供了
transferTo
方法实现将数据直接传输到OutputStream中
package com.lagou.newproperties;
import java.io.*;
public class InputStreamTest {
public static void main(String[] args) {
InputStream inputStream = null;
OutputStream outputStream =null;
//transferTo
try {
inputStream = new FileInputStream("d:/a.txt");
outputStream = new FileOutputStream("d:/b.txt");
inputStream.transferTo(outputStream);
outputStream.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null!= outputStream){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null!=inputStream){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Java10新特性
Java10概述
- Java10于2018年3月发布,改进的关键点包括一个本地类型推断、一个垃圾回收的增强。
- Java10计划只是一个短期版本,因此公开更新将在六个月内结束,9月份发布的Java11将是Java的长期支持(LTS)版本,LTS版本的发布每三年发布一次。
局部变量的推断
基本概念
- Java10可以使用var作为局部变量类型推断标识符,此符号仅适用于局部变量,增强for循环的索引,以及传统for循环的本地变量。
- 它不能使用于方法形式参数,构造函数形式参数,方法返回类型,字段,catch形式参数或任何其他类型的变量声明。
实际意义
- 标识符var不是关键字,只是一个保留的类型名称。这意味着var用作变量,方法名或包名的代码不会受到影响,但var不能作为类或则接口的名字。
- 避免了信息冗余。
- 对齐了变量名。
- 更容易阅读。
public class VarTest {
public static void main(String[] args) {
// 由初始值可以推断出变量的类型,因此可以使用var取代
//int num = 10;
var num = 10;
//List<Integer> list = new LinkedList<>();
var list = new LinkedList<Integer>();
list.add(10);
for (var v : list) {
System.out.println(v);
}
for (var i = 0; i < 10; i++) {}
}
}
Java11新特性
Java11概述
- Java11于2018年9月正式发布,这是 Java 大版本周期变化 后的第一个长期支持版本,非常值得关注。
简化的编译操作
- 在Java11中可以使用java命令一次性进行编译和运行操作。
- 执行源文件中的第一个类必须包含主方法。
- 不可以使用其它源文件中自定义的类
String新增的方法
方法声明 | 功能介绍 |
boolean isBlank() | 判断字符串是否为空或只包含空白代码点 |
Optional map(Function<? super T,? extends U> mapper) | 根据参数指定规则的结果来得到Optional类型的对象 |
T orElse(T other) | 若该值存在就返回,否则返回other的数值。 |