1.Lamda表达式
Lambda表达式的作用主要是用来简化接口的创建,使用Lambda表达式接口必须是函数式接口
- 语法格式一:无参,无返回值,Lambda体只需一条语句
- 语法格式二:Lambda只需要一个参数时,参数的小括号可以省略
- 语法格式三:当Lambda体只有一条语句时,return与大括号可以省略
- 语法格式四:参数的数据类型可以省略
@Test
public void testLambda() {
new Thread(() -> {
for (int i = 0; i < 10; i++) {
log.info(" {} ", i);
}
}).start();
}
2.函数式接口
函数式接口只能有一个抽象方法,使用@FunctionalInterface注解可以检查是否是函数式接口
- 自定义函数式接口
@FunctionalInterface
interface MyFunc<T> {
T getValue(T t);
}
- 四大内置核心函数式接口
Consumner<T> : 消费型接口
void accept(T t);
用途:对类型为T的对象应用操作,包含方法:void accept(T t);
@Test
public void testConsume() {
pay(1000, money -> System.out.println("购物消费了" + money + "元"));
}
private void pay(int money, Consumer<Integer> consumer) {
consumer.accept(money);
}
Supplier<T> :供给型接口
T get();
用途:返回类型为T的对象,包含方法:T get();
@Test
public void testSupplier() {
List<Integer> list = getNumList(10, () -> (int)(Math.random() * 100));
for (int num : list) {
System.out.println("supplier" + num);
}
}
private List<Integer> getNumList(int num, Supplier<Integer> supplier) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
list.add(supplier.get());
}
return list;
}
Function<T , R>:函数式接口
R apply(T t);
用途:对类型为T的对象应用操作,并返回结果,结果是R类型的对象,包含方法:R apply(T t);
@Test
public void testFunction() {
String name = "Jack Yang";
System.out.print(strHandler(name, String::toLowerCase));
}
private String strHandler(String str, Function<String, String> func) {
return func.apply(str);
}
Predicate<T>:断言型接口
boolean test(T t);
用途:确定类型为T的对象是否满足某约束,并返回boolean值,包含方法:boolean test(T t);
@Test
public void testPredicate() {
List<String> list = filterStr(
Arrays.asList("jackyang", "jackie", "jordan", "ronaldo", "figo", "zidane"),
s -> s.length() >= 6
);
for (String name : list) {
System.out.println(name);
}
}
private List<String> filterStr(List<String> list, Predicate<String> predicate) {
List<String> handleList = new ArrayList<>();
for(String str : list) {
if(predicate.test(str)) {
handleList.add(str);
}
}
return handleList;
}
其他函数式接口(http://www.runoob.com/java/java8-functional-interfaces.html)
3.方法引用
方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致
若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName
构造器的参数列表,需要与函数式接口中参数列表保持一致
三种语法格式
- 对象::实例方法
- 类::静态方法
- 类::实例方法
4.Stream API
集合讲的是数据,流讲的是计算!
- Stream 自己不会存储元素。
- Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
- Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
Stream流的操作三个步骤
- 创建流(数据源:集合、数组)
- 中间操作(操作链,对数据源数据进行计算)
- 终止操作(产生结果)
创建Stream流
- 集合创建流(Collection 接口扩展)
default Stream<E> stream() : 返回一个顺序流
default Stream<E> parallelStream() : 返回一个并行流
- 数组创建流(Arrays 静态方法)
static <T> Stream<T> stream(T[] array): 返回一个流
- 值创建流(静态方法 Stream.of())
public static<T> Stream<T> of(T... values) : 返回一个流
- 创建无限流(函数创建 iterate和generate)
迭代 public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
生成 public static<T> Stream<T> generate(Supplier<T> s)
@Slf4j
public class StreamTest extends AdminApiApplicationTests {
@Data
class Student {
private String name;
private Integer age;
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
}
@Test
public void testStreamCreate() {
System.out.println("-----------集合创建流-----------");
Arrays.asList("jackyang", "", "jordan", "helloworld", "hellokitty").stream().filter(s -> s.length() > 8).forEach(System.out::println);
System.out.println("-----------数据创建流-----------");
Student[] students = new Student[]{
new Student("jackyang", 30),
new Student("jordan", 40),
new Student("kitty", 18)
};
Arrays.stream(students).filter(student -> student.age > 20).forEach(System.out::println);
System.out.println("-----------值创建流-----------");
Stream.of(students).filter(student -> student.age < 20).forEach(System.out::println);
System.out.println("-----------创建无限流-----------");
Stream.iterate(5, s -> s + 2).limit(10).forEach(System.out::println);
Stream.generate(() -> (int)(Math.random() * 100)).limit(10).forEach(System.out::println);
}
}
中间操作
中间操作不会执行任何的操作,而是在终止操作时一次性全部处理,称为“惰性求值”
- filter(Predicate p) 接收 Lambda 从流中排除某些元素
- distinct() 通过流所生成元素的 hashCode() 和 equals() 去 除重复元素
- limit(long maxSize) 截断流,使其元素不超过给定数量
- skip(long n) 跳过元素,返回一个剔除了前 n 个元素的流,若流中元素不足n个,则返回一个空流
- map(Function f) 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
- mapToDouble(ToDoubleFunction f) 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 DoubleStream
- mapToInt(ToIntFunction f) 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 IntStream
- mapToLong(ToLongFunction f) 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 LongStream
- flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
- sorted() 产生一个新流,其中按自然顺序排序
- sorted(Comparator comp) 产生一个新流,其中按比较器顺序排序
终止操作
终止操作会从流的流水线生成结果,其结果可以是任何不是流的值,例如:List、Integer,甚至是 void
匹配
- allMatch(Predicate p) 检查是否匹配所有元素
- anyMatch(Predicate p) 检查是否至少匹配一个元素
- noneMatch(Predicate p) 检查是否没有匹配所有元素
查找
- findFirst() 返回第一个元素
- findAny() 返回当前流中的任意元素
- count() 返回流中元素总数
- max(Comparator c) 返回流中最大值
- min(Comparator c) 返回流中最小值
遍历
- forEach(Consumer c) 内部迭代
规约
- reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值,返回 T
- reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值,返回 Optional<T>
收集
- collect(Collector c) 将流转换为其他形式,接收一个 Collector接口的实现
用于给Stream中元素做汇总的方法
toList
List<T>
把流中元素收集到List
List<Employee> emps = list.stream().collect(Collectors.toList());
Set<T>
把流中元素收集到Set
Set<Employee> emps = list.stream().collect(Collectors.toSet());
toCollection
Collection<T>
把流中元素收集到创建的集合
Collection<Employee>emps =list.stream().collect(Collectors.toCollection(ArrayList::new));
counting
Long
计算流中元素的个数
long count = list.stream().collect(Collectors.counting());
summingInt
Integer
对流中元素的整数属性求和
int total = list.stream().collect(Collectors.summingInt(Employee::getSalary));
averagingInt
Double
计算流中元素Integer属性的平均 值
double avg = list.stream().collect(Collectors.averagingInt(Employee::getSalary));
summarizingInt
IntSummaryStatistics
收集流中Integer属性的统计值。 如:平均值
IntSummaryStatistics iss = list.stream().collect(Collectors.summarizingInt(Employee::getSalary));
joining
String
连接流中每个字符串
String str = list.stream().map(Employee::getName).collect(Collectors.joining());
maxBy
Optional<T>
根据比较器选择最大值
Optional<Emp>max = list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));
minBy
Optional<T>
根据比较器选择最小值
Optional<Emp> min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));
reducing
归约产生的类型
从一个作为累加器的初始值开始,利用BinaryOperator与 流中元素逐个结合,从而归约成单个值
int total = list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum));
collectingAndThen
转换函数返回的类型
包裹另一个收集器,对其结 果转换函数
int how = list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
groupingBy
Map<K, List<T>>
根据某属性值对流分组,属 性为K,结果为V
Map<Emp.Status, List<Emp>> map= list.stream() .collect(Collectors.groupingBy(Employee::getStatus));
partitioningBy
Map<Boolean, List<T>>
根据true或false进行分区
Map<Boolean,List<Emp>> vd = list.stream().collect(Collectors.partitioningBy(Employee::getManage));
5.并行流与串行流
并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流
可以使用parallel() 与 sequential() 在并行流与串行流之间进行切换
Fork/Join框架: 就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行join汇总.
采用 “工作窃取”模式(work-stealing): 当执行新的任务时它可以将其拆分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中
6.新时间日期 API
- LocalDate
- LocalTime
- LocalDateTime
now() 静态方法,根据当前时间创建对象
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now(); LocalDateTime localDateTime = LocalDateTime.now();
of() 静态方法,根据指定日期/时间创建 对象
LocalDate localDate = LocalDate.of(2016, 10, 26);
LocalTime localTime = LocalTime.of(02, 22, 56);
LocalDateTime localDateTime = LocalDateTime.of(2016, 10, 26, 12, 10, 55);
plusDays, plusWeeks, plusMonths, plusYears 向当前 LocalDate 对象添加几天、 几周、几个月、几年
minusDays, minusWeeks, minusMonths, minusYears 从当前 LocalDate 对象减去几天、 几周、几个月、几年
plus, minus 添加或减少一个 Duration 或 Period
withDayOfMonth, withDayOfYear, withMonth, withYear 将月份天数、年份天数、月份、年 份修改为指定的值并返回新的 LocalDate 对象
getDayOfMonth 获得月份天数(1-31)
getDayOfYear 获得年份天数(1-366)
getDayOfWeek 获得星期几(返回一个 DayOfWeek 枚举值)
getMonth 获得月份, 返回一个 Month 枚举值
getMonthValue 获得月份(1-12)
getYear 获得年份
until 获得两个日期之间的 Period 对象, 或者指定 ChronoUnits 的数字
isBefore, isAfter 比较两个 LocalDate
isLeapYear 判断是否是闰年
- Instant 时间戳
Duration:用于计算两个时间间隔
Period:用于计算两个日期间隔
- TemporalAdjuster: 时间校正器
- 时间格式化
@Test
public void testDateFormat() {
LocalDateTime local = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
System.out.println(formatter.format(local));
}
@Test
public void testDateFormat() {
LocalDateTime local = LocalDateTime.now();
String dateTime = local.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss"));
System.out.println(dateTime);
}
@Test
public void testDateFormat() {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
String strDate = "2018年05月12日 14:31:33";
LocalDateTime ldt = LocalDateTime.now();
LocalDateTime newDate = ldt.parse(strDate, dateTimeFormatter);
System.out.println(newDate);
}
7.接口中默认方法与静态方法
接口默认方法的类优先原则
若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时选择父类中的方法
如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略
接口冲突:
如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突
8.Optional类
常用方法:
Optional.of(T t) : 创建一个 Optional 实例
Optional.empty() : 创建一个空的 Optional 实例
Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
isPresent() : 判断是否包含值
orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
flatMap(Function mapper):与 map 类似,要求返回值必须是Optional