文章目录
Lambda:
为什么使用Lambda表达式 ?
Lambda是一个匿名函数,我们可以把Lambda
表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使
Java的语言表达能力得到了提升。
Lambda表达式语法 ?
Lambda表达式在Java语言中引入了一个新的语法元素和操作符。这个操作符为“->”,该操作符被称为Lambda操作符或剪头操作符。它将Lambda分为两个部分:
左侧:指定了Lambda表达式需要的所有参数
右侧:指定了Lambda体,即Lambda表达式要执行的功能。
什么是函数式接口 ?
-
只包含一个抽象方法的接口,称为函数式接口。
-
你可以通过Lambda表达式来创建该接口的对象。(若Lambda表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)。
-
我们可以在任意函数式接口上使用@FunctionalInterface注解,这样做可以检查它是否是一个函数式接口,同时javadoc也会包含一条声明,说明这个接口是一个函数式接口。
Lambda 表达式的基本语法:
import org.junit.Test;
import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
/**
* Lambda 表达式的基本语法:Java8中引用了一个新的操作符 "->"
* 箭头将Lambda表达式拆分成两部分:
*
* 左侧:Lambda 表达式的参数列表
* 右侧:Lambda 表达式中所需的功能,即Lambda体
*
* 能省则省
* 左右遇一括号省
* 左侧推断类型省
*
* 二、Lambda 表达式需要函数式接口的支持
* 函数式接口:接口中只有一个抽象方法的接口,可以使用注解@FunctionalInterface 修饰
*
*
* @author xiaofei
* @create 2019-07-10 上午 11:58
*/
public class TestLambda1 {
List<Employee> emps = Arrays.asList(
new Employee("xf1", 12, 9999.99),
new Employee("xf2", 43, 555555.5),
new Employee("xf3", 2, 666.5),
new Employee("xf4", 45, 333.5),
new Employee("xf5", 89, 777.6)
);
/**
* 语法格式一:无参数,无返回值
*/
@Test
public void test1() {
int num = 0;
Runnable r = new Runnable() {
@Override
public void run() {
System.err.println("Hello World!" + num);
}
};
r.run();
System.err.println("----------------------");
Runnable r1 = () -> System.err.println("Hello Lambda!" + num);
r1.run();
}
/**
* 语法格式二:有一个参数,并且无返回值
*
* 参数的小括号可以省略
*/
@Test
public void test2() {
Consumer<String> consumer = x -> System.err.println(x);
consumer.accept("xiaofei");
}
/**
* 语法格式三:有两个参数,并且有返回值
*
*/
@Test
public void test3() {
BinaryOperator<Long> bo = (x,y) -> {
System.err.println("实现函数接口方法!");
return x + y;
};
System.err.println(bo.apply(1L,2L));
}
/**
* 语法格式四:当Lambda体中只有一条语句时,return与大括号都可以省略不写!
*
*/
@Test
public void test4() {
BinaryOperator<Integer> bo = (x,y) -> x + y;
System.err.println(bo.apply(1,2));
}
/**
* 语法格式五:Lambda 表达式的参数列表的数据类型可以省略不写,
* 因为JVM编译器通过上下文推断出数据类型,即"类型推断"
*
*/
@Test
public void test5() {
show(new HashMap<>());
}
public void show(Map<String, String> map) {
}
/**
* 调用Collections.sort()方法,通过排序比较两个Employee(先按照年龄比,年龄相同按照姓名比)
*/
@Test
public void test6() {
Collections.sort(emps,(e1,e2)->{
if (e1.getAge() == e2.getAge()) {
return e1.getName().compareTo(e2.getName());
}else {
return Integer.compare(e1.getAge(), e2.getAge());
}
});
for (Employee emp : emps) {
System.err.println(emp);
}
}
@Test
public void test7(){
BinaryOperator<String> bo = (x, y) -> x.toUpperCase();
}
}
Lambda 四大内置核心函数式接口:
Consumer:消费型接口:
@Test
public void test1() {
happy(10000, (m) -> System.out.println("消费" + m));
}
public void happy(double money, Consumer<Double> con) {
con.accept(money);
}
Supplier:供给型接口:
@Test
public void test2() {
List<Integer> numList = getNumList(10, () -> (int) (Math.random() * 100));
System.err.println(numList);
}
/**
* 需求:产生一些整数,并放入集合中
*
* @param num
* @param sup
* @return
*/
public List<Integer> getNumList(int num, Supplier<Integer> sup) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
list.add(sup.get());
}
return list;
}
Function: 函数型接口:
@Test
public void test3() {
String str = strHandler("xiaofei", (s) -> s.toUpperCase());
System.err.println(str);
}
/**
* 需求:用于处理字符串
*/
public String strHandler(String str, Function<String, String> fun) {
return fun.apply(str);
}
Predicate:断言型接口:
@Test
public void test4() {
List<String> list = Arrays.asList("Hello", "xiaofei","ok");
List<String> strList = filterStr(list, (s) -> s.length() > 3);
System.err.println(strList);
}
/**
* 需求: 将满足条件的字符串,放入集合中
*/
public List<String> filterStr(List<String> list, Predicate<String> pre) {
List<String> strList = new ArrayList<>();
for (String str : list) {
if (pre.test(str)) {
strList.add(str);
}
}
return strList;
}
方法引用与构造器引用:
import org.junit.Test;
import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* 一、方法引用:若Lambda 体中的内容有方法已经实现了,我们可以使用"方法引用"
*
* 三种语法格式:
*
* 对象::实例方法名
*
* 类::静态方法名
*
* 类::实例方法名
*
* 注意:
* Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中抽象的方法的函数列表和返回值类型保持一致!
* Lambda 参数列表中第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::method
*
* 二、构造器引用:
* 格式:
* ClassName::new
*
* 三、数组引用:
*
* @author xiaofei
* @create 2019-07-10 下午 04:32
*/
public class TestMethodRef {
/**
* 数组引用
*/
@Test
public void test5() {
Function<Integer, String[]> fun = (x) -> new String[x];
String[] strs = fun.apply(10);
System.err.println(strs.length);
Function<Integer,String[]> fun2 = String[]::new;
String[] strs2 = fun2.apply(20);
System.err.println(strs2.length);
}
/**
* 构造器引用
*/
@Test
public void test4() {
Supplier<Employee> sup = () -> new Employee();
Supplier<Employee> sup2 = Employee::new;
System.err.println(sup2.get());
}
/**
* 类::实例方法名
*/
@Test
public void test3() {
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
BiPredicate<String, String> bp2 = String::equals;
System.err.println(bp2.test("a2", "a"));
}
/**
* 类::静态方法名
*/
@Test
public void test2() {
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
Comparator<Integer> com2 = Integer::compare;
System.err.println(com2.compare(3, 2));
}
/**
* 对象::实例方法名
*/
@Test
public void test1() {
PrintStream ps1 = System.out;
Consumer<String> con = (x) -> ps1.println(x);
PrintStream ps2 = System.out;
Consumer<String> con1 = ps2::println;
Consumer<String> con2 = System.out::println;
con2.accept("xiaofei");
}
}
创建 Stream:
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/**
* 一、Stream 的三个操作步骤:
*
* 1、创建Stream
*
* 2、中间操作
*
* 3、终止操作
*
* @author xiaofei
* @create 2019-07-10 下午 05:12
*/
public class TestStreamAPI1 {
/**
* 创建Stream
*/
@Test
public void test1() {
// 1.通过Collection系列集合提供的stream()或parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
// 2.通过Arrays 中的静态方法stream()获取数组流
Employee[] employees = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(employees);
// 3.通过Stream类中的静态方法of()
Stream<String> stream3 = Stream.of("aa", "bb", "cc");
// 4.创建无限流
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
stream4.limit(10).forEach(System.out::println);
// 生成5个随机数
Stream.generate(() -> Math.random()).limit(5).forEach(System.out::println);
}
}
Stream_筛选与切片
emps:
List<Employee> emps = Arrays.asList(
new Employee("xf1", 12, 9999.99),
new Employee("xf2", 43, 555555.5),
new Employee("xf1", 12, 9999.99),
new Employee("xf1", 12, 9999.99),
new Employee("xf4", 45, 333.5),
new Employee("xf5", 89, 777.6)
);
filter–接收Lambda,从流中排除某些元素:
@Test
public void test1() {
// 中间操作: 不会执行任何操作
Stream<Employee> stream = emps.stream()
.filter((e) -> e.getAge() > 35);
// 终止操作:一次性执行全部内容,即"惰性求职"
stream.forEach(System.out::println);
}
limit–截断流,使其元素不超过给定数量:
@Test
public void test2() {
emps.stream().limit(2).forEach(System.out::println);
}
skip(n)–跳过元素:
/**
* skip(n)--跳过元素
*
* 返回一个拐掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补
*/
@Test
public void test3() {
// 跳过第一条元素
emps.stream().skip(1).forEach(System.out::println);
}
distinct–排除重复的:
/**
* distinct--筛选
* 通过流所生成元素的hashCode()和equals()去除重复元素
*/
@Test
public void test4() {
emps.stream()
.skip(1)
.distinct()
.forEach(System.out::println);
}
map-映射:
/*
映射:
map---接收Lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap---接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
*/
@Test
public void test5() {
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");
list.stream()
.map((str) -> str.toUpperCase())
.forEach(System.out::println);
System.out.println("-------------------------");
emps.stream()
.map(Employee::getName)
.forEach(System.out::println);
System.out.println("-------------------------");
list.stream()
.flatMap(TestStreamAPI2::filterCharacter)
.forEach(System.out::println);
}
public static Stream<Character> filterCharacter(String str) {
List<Character> list = new ArrayList<>();
for (Character ch : str.toCharArray()) {
list.add(ch);
}
return list.stream();
}
sorted-排序:
/*
排序:
sorted()---自然排序
sorted(Comparator com)---定制排序
*/
@Test
public void test6() {
List<String> list = Arrays.asList("ccc", "bbb", "aaa", "ddd");
list.stream()
.sorted()
.forEach(System.out::println);
System.out.println("---------------------------");
emps.stream()
.sorted((e1,e2) -> {
// 如果年龄相等按照姓名排序否则按照年龄排序
if (e1.getAge().equals(e2.getAge())) {
return e1.getName().compareTo(e2.getName());
}else {
return e1.getAge().compareTo(e2.getAge());
}
}).forEach(System.out::println);
}
终止操作:
emps:
List<Employee> emps = Arrays.asList(
new Employee("xf1", 12, 9999.99, Employee.Status.BUSY),
new Employee("xf2", 43, 555555.5, Employee.Status.FREE),
new Employee("xf1", 12, 9999.99, Employee.Status.VOCATION),
new Employee("xf1", 12, 9999.99, Employee.Status.FREE),
new Employee("xf4", 45, 333.5, Employee.Status.BUSY)
);
查找:
/*
allMatch-检查是否匹配所有元素
anyMatch-检查是否至少匹配一个元素
noneMatch-检查是否没有匹配所有元素
findFirst—返回第一个元素
findAny一返回当前流中的任意元素
*/
@Test
public void test1() {
boolean b1 = emps.stream()
.allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println("是否匹配全部" + b1);
System.out.println("-----------------------------");
boolean b2 = emps.stream()
.anyMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println("是否匹配其中一个" + b2);
System.out.println("-----------------------------");
boolean b3 = emps.stream()
.noneMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println("是否没有匹配所有元素" + b3);
System.out.println("-----------------------------");
Optional<Employee> op = emps.stream()
.sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
.findFirst();
System.out.println("获取工资最低的" + op.get());
System.out.println("-----------------------------");
Optional<Employee> op2 = emps.parallelStream()
.filter((e) -> e.getStatus().equals(Employee.Status.FREE))
.findAny();
System.out.println("返回当前流中的任意元素" + op2.get());
}
匹配:
/*
count—返回流中元素的总个数
max—返回流中最大值
min—返回流中最小值
*/
@Test
public void test2() {
long count = emps.stream()
.count();
System.out.println("总数:" + count);
System.out.println("-------------------------");
Optional<Employee> max = emps.stream()
.max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println("返回工资最大的" + max.get());
System.out.println("-------------------------");
Optional<Double> min = emps.stream()
.map(Employee::getSalary)
.min(Double::compare);
System.out.println("返回工资最小的" + min.get());
}
规约(用于计算总和):
/*
归约
reduce(T identity,Binaryoperator)/reduce(Binaryoperator)
可以将流中元素反复结合起来,得到一个值。
*/
@Test
public void test3() {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
Integer reduce = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(reduce);
System.out.println("------------------------------");
Optional<Double> op = emps.stream()
.map(Employee::getSalary)
.reduce(Double::sum);
System.out.println("获取所有工资总和:" + op.get());
}
收集:
/*
收集
collect一将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
*/
@Test
public void test5() {
Long collect = emps.stream()
.collect(Collectors.counting());
System.out.println("查询总数:" + collect);
System.out.println("---------------------------");
Double collect1 = emps.stream()
.collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println("查询工资的平均值:" + collect1);
System.out.println("---------------------------");
Double collect2 = emps.stream()
.collect(Collectors.summingDouble(Employee::getSalary));
System.out.println("查询工资的总和:" + collect2);
System.out.println("---------------------------");
Optional<Employee> collect3 = emps.stream()
.collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println("查询工资的最大值:" + collect3.get().getSalary());
System.out.println("---------------------------");
Optional<Double> collect4 = emps.stream()
.map(Employee::getSalary)
.collect(Collectors.minBy(Double::compare));
System.out.println("查询工资的最小值:" + collect4.get());
System.out.println("---------------------------");
Map<Employee.Status, List<Employee>> collect5 = emps.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
System.out.println("根据状态分组" + collect5);
System.out.println("---------------------------");
Map<Employee.Status, Map<String, List<Employee>>> collect6 = emps.stream()
.collect(Collectors.groupingBy(Employee::getStatus,
Collectors.groupingBy((e) -> {
if (((Employee) e).getAge() <= 35) {
return "青年";
} else if (((Employee) e).getAge() <= 50) {
return "中年";
} else {
return "老年";
}
})));
System.out.println("多级分组-根据状态和年龄分组:" + collect6);
System.out.println("---------------------------");
Map<Boolean, List<Employee>> collect7 = emps.stream()
.collect(Collectors.partitioningBy((e) -> e.getSalary() > 8000));
System.out.println("满足条件和不满足条件的两个区域:" + collect7);
System.out.println("---------------------------");
DoubleSummaryStatistics collect8 = emps.stream()
.collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(collect8.getSum());
System.out.println(collect8.getAverage());
System.out.println(collect8.getCount());
System.out.println(collect8.getMax());
System.out.println(collect8.getMin());
System.out.println("---------------------------");
String collect9 = emps.stream()
.map(Employee::getName)
.collect(Collectors.joining(","));
System.err.println("获取所有名字以逗号隔开:" + collect9);
}
新时间日期API:
Java8中加入了对时区的支持,带时区的时间为分别为:ZonedDate、ZonedTime、ZonedDateTime
其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式例如:Asia/Shanghai等
ZoneId:该类中包含了所有的时区信息
getAvailableZoneIds() :可以获取所有时区时区信息
of(id) :用指定的时区信息获取ZoneId对象
代码:
import org.junit.Test;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Set;
/**
* Java8 时间
*
* @author xiaofei
* @create 2019-07-10 下午 10:38
*/
public class TestLocalDateTime {
// 1.LocalDate LocalTime LocalDateTime
@Test
public void test1() {
LocalDateTime ldt = LocalDateTime.now();
System.err.println("获取时间:" + ldt);
LocalDateTime of = LocalDateTime.of(2015, 10, 10, 8, 12, 36, 33);
System.err.println("自定义时间:" + of);
LocalDateTime localDateTime1 = ldt.plusYears(2);
System.err.println("增加2年:" + localDateTime1);
LocalDateTime localDateTime2 = ldt.minusYears(2);
System.err.println("减加2年:" + localDateTime2);
// 获取时分秒
System.err.println(ldt.getYear());
System.err.println(ldt.getMonthValue());
System.err.println(ldt.getDayOfMonth());
System.err.println(ldt.getHour());
System.err.println(ldt.getMinute());
System.err.println(ldt.getSecond());
}
// 2.Instant: 时间戳
@Test
public void test2() {
// 默认获取UTC 时区
Instant instant = Instant.now();
System.err.println(instant);
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
System.err.println("推移8个小时:" + offsetDateTime);
System.err.println("时间戳:" + offsetDateTime.toEpochSecond());
}
// 3.Duration: 计算两个时间之间的间隔
// Period:计算两个日期之间的间隔
@Test
public void test3() throws InterruptedException {
Instant ins1 = Instant.now();
Thread.sleep(100);
Instant ins2 = Instant.now();
Duration between = Duration.between(ins1, ins2);
System.err.println("间隔:" + between.toMillis());
System.err.println("*******************************");
LocalTime lt1 = LocalTime.now();
Thread.sleep(100);
LocalTime lt2 = LocalTime.now();
System.err.println("间隔:" + Duration.between(lt1, lt2).toMillis());
System.err.println("-------------------------------");
LocalDate ld1 = LocalDate.of(2019, 1, 1);
Thread.sleep(100);
LocalDate ld2 = LocalDate.now();
System.err.println("星期之间的间隔:" + Period.between(ld1, ld2).getMonths());
}
// 4.DateTimeFormatter: 格式化时间/日期
@Test
public void test4() {
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE;
LocalDateTime ldt = LocalDateTime.now();
System.err.println(dtf.format(ldt));
DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
System.err.println("自定义格式化:" + dtf2.format(ldt));
LocalDateTime parse = ldt.parse(dtf2.format(ldt), dtf2);
System.err.println("把字符串转换为日期:" + parse);
}
// 5.ZoneDate、ZonedTime、ZonedDateTime
@Test
public void test5() {
// 时区
Set<String> az = ZoneId.getAvailableZoneIds();
az.forEach(System.out::println);
// 指定时区
LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
System.err.println(now);
}
}
重复注解与类型注解
MyAnnotation:
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
/**
* 注解
*
* TYPE_PARAMETER --- 注解类型
* @author xiaofei
*/
@Repeatable(MyAnnotations.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "xiaofei";
}
MyAnnotations:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
/**
*
* @author xiaofei
*/
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {
MyAnnotation[] value();
}
TestAnnotation:
import org.junit.Test;
import java.lang.reflect.Method;
/**
* 重复注解与类型注解
*
* @author xiaofei
* @create 2019-07-10 下午 11:11
*/
public class TestAnnotation {
/**
* 获取注解里面的值
*/
@Test
public void test1() throws NoSuchMethodException {
Class<TestAnnotation> clazz = TestAnnotation.class;
Method m1 = clazz.getMethod("show");
MyAnnotation[] annotationsByType = m1.getAnnotationsByType(MyAnnotation.class);
for (MyAnnotation myAnnotation : annotationsByType) {
System.err.println(myAnnotation.value());
}
}
@MyAnnotation("xiaofei")
@MyAnnotation("xiaofei2")
public void show(@MyAnnotation("abc") String id) {
}
}
Model层-Employee代码
/**
* Employee
* @author xiaofei
* @create 2019-07-10 上午 11:10
*/
public class Employee {
private String name;
private Integer age;
private double salary;
private Status status;
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public String getName() {
return name;
}
public Employee() {
}
public Employee(String name, Integer age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public Employee(String name, Integer age, double salary, Status status) {
this.name = name;
this.age = age;
this.salary = salary;
this.status = status;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
", status=" + status +
'}';
}
public enum Status{
FREE,
BUSY,
VOCATION;
}
}
JUnit 需要导入的jar包:
hamcrest-core-1.1.jarjunit-4.12.jar
下载地址:
http://central.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar
http://central.maven.org/maven2/junit/junit/4.12/junit-4.12.jar
导入JAR:
QQ群:470765097