1.lambda表达式
Lambda 允许把函数作为参数传递进方法中
// 类型声明 MathOperation addition = (int a, int b) -> a + b;
// 不用类型声明 MathOperation subtraction = (a, b) -> a - b;
// 大括号中的返回语句 MathOperation multiplication = (int a, int b) -> { return a * b; };
Lambda 表达式只能引用标记了 final 的外层局部变量,lambda 表达式的局部变量可以不用声明为 final,但是必须不可被后面的代码修改
2.方法引用
构造器引用:它的语法是Class::new,或者更一般的Class< T >::new
public static Car create(final Supplier<Car> supplier) { return supplier.get(); }
final Car car = Car.create( Car::new );
静态方法引用:它的语法是Class::static_method
public static void collide(final Car car) { System.out.println("Collided " + car.toString()); }
cars.forEach( Car::collide );
特定类的任意对象的方法引用:它的语法是Class::method
public void repair() { System.out.println("Repaired " + this.toString()); }
cars.forEach( Car::repair );
特定对象的方法引用:它的语法是instance::method
public void follow(final Car another) { System.out.println("Following the " + another.toString()); }
final Car police = Car.create( Car::new );
cars.forEach( police::follow );
3.Stream
Stream(流)是一个来自数据源的元素队列并支持聚合操作
数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
forEach limit sorted
Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);
map
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 获取对应的平方数
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
filter
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
long count = strings.stream().filter(string -> string.isEmpty()).count();
Collectors
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println("筛选列表: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);
(1)Stream创建
1) 通过参数序列创建Stream
// 利用可变参数直接构造Stream,相比Arrays.stream()更简单
// 下面语句创建的流内容:10,20,30,40,50
final IntStream stream = IntStream.of(10, 20, 30, 40, 50);
// 下面语句创建的流内容:red,blue,green
final Stream<String> colorStream = Stream.of("red", "blue", "green");
2) 通过数组创建Stream
相比Stream.of(),不用区分基础数据类型,但参数只能是数组,不支持参数序列创建
final Integer[] numbers = {10, 20, 30, 40, 50, 60};
final Stream<Integer> numberStream = Arrays.stream(numbers);
final int[] intNumbers = {10, 20, 30, 40, 50, 60};
final IntStream result = Arrays.stream(intNumbers);
3) 通过集合创建Stream
final Collection<Integer> collection = Lists.newArrayList(10, 20, 30, 40, 50, 60);
final Stream<Integer> numberStream = collection.stream();
4) 通过集合创建并行Stream
final Collection<Integer> numbers = Lists.newArrayList(10, 20, 30, 40, 50, 60);
// 直接创建并行流
Stream<Integer> numberStream = numbers.parallelStream();
// 将串行流转换为并行流
numberStream = numbers.stream().parallel();
5) 通过IO方式创建Stream
// 读取文件的内容,生成stream流
final Stream<String> stream = Files.lines(Paths.get("data.txt"), Charsets.UTF_8);
// 获取目录下的文件列表信息
final Stream<Path> listFile = Files.list(Paths.get("/"));
6) 通过生成器创建Stream
SecureRandom random = SecureRandom.getInstanceStrong();
// 直接传入instance::method
// 下面语句创建的result包含10个随机数
Stream<Integer> result = Stream.generate(random::nextInt).limit(10);
// 直接传入lambda表达式
// 下面语句创建的result包含10个元素,每个值由根据当前时间 % 100计算得来
// 以某次执行为例,result包含36,3,40,71,46,43,68,97,38,92
result = Stream.generate(() -> (int) (System.nanoTime() % 100)).limit(10);
7) 通过iterate创建Stream
// 以0为种子,f(n) = n + 3, f(f(n)) ...
// 下面语句创建的Stream内容:0 3 6 9 12 15 18 21 24 27
Stream.iterate(0, n -> n + 3).limit(10).forEach(Stubs::doWhatever);
8) 通过区间创建整数序列Stream
// 通过range、rangeClosed生成序列,该序列为数学中的区间序列。
// 生成[-100, 100)区间的元素序列,不包括end元素100
final IntStream range = IntStream.range(-100, 100);
// 由于start > end,不符合区间定义,返回空区间,Stream中元素长度为0
final IntStream emptyRange = IntStream.range(100, -100);
// 生成[-100,100]区间的元素序列,包含end元素100
final IntStream rangeClosed = IntStream.rangeClosed(-100, 100);
// LongStream range生成
// 生成[-100, 100)区间的元素序列,不包括end元素100
final LongStream longRange = LongStream.range(-100L, 100L);
// 生成[-100,100]区间的元素序列,包含end元素100
final LongStream longRangeClosed = LongStream.rangeClosed(-100L, 100L);
(1)Stream基础操作
1) 计算Stream大小
// 计算Stream中元素的格式,count为特殊的reduce操作,对于sum(), max(), min(), average(),count()等操作不建议直接使用reduce()
// 等同于stream.mapToLong(e -> 1L).sum();
long count = Stream.of().count(); // count = 0
count = Stream.of(10).count(); // count = 1
count = Stream.of(10, 20, 30, 40, 50).count(); // count = 5
1) Stream转换为字符串
final Stream<String> stream = Stream.of("red", "blue", "green");
// 执行结果:colors值为red|blue|green
String colors = stream.collect(Collectors.joining("|"));
2) Stream转换为数组
final Stream<String> stream = Stream.of("red", "blue", "green");
// 执行结果:colors数组为[red, blue, green]
String[] colors = stream.toArray(String[]::new);
3) Stream转换为ArrayList
final Stream<String> stream = Stream.of("red", "blue", "green");
// colors类型为ArrayList,结果为[red, blue, green]
List<String> colors = stream.collect(Collectors.toList());
4) Stream转换为List
不同业务场景对性能、内存占用等有不同的诉求。对于ArrayList不满足的场景,可将Stream元素收集到指定类型的List,如:LinkedList。
final Stream<String> stream = Stream.of("red", "blue", "green");
// Stream转换的List类型为LinkedList
// 执行结果:colors结果为[red, blue, green]
List<String> colors = stream.collect(Collectors.toCollection(LinkedList::new));
5) Stream转换为指定类型Collection
final Stream<String> stream = Stream.of("red", "blue", "green");
// colors为LinkedHashSet,对于其他的类型在toCollection()方法参数中指定
Set<String> colors = stream.collect(Collectors.toCollection(LinkedHashSet::new));
6) Stream转换为Set
final Stream<String> stream = Stream.of("red", "blue", "green");
// 默认转换为HashSet
// 执行结果:colors值为[red, green, blue]
final Set<String> colors = stream.collect(Collectors.toSet());
7) Stream转换为Map
Collectors.toMap()需要保证Key唯一性,如果不唯一,则需给出合并策略
Collectors.toMap()需要保证Stream元素为NonNull,且映射到Map的value值必须为NonNull
final Stream<User> stream = Stream.of(new User("1", "Jerry", "Male"), new User("2", "Kitty", "Female"));
// 以User的ID作为key,User实例作为value,转换过程默认使用的是HashMap
// user.getId()必须是唯一的,否则会抛出java.lang.IllegalStateException: Duplicate key
// 执行结果:map值为
// {1=User(id=1, username=Jerry, salary=0, gender=Male), 2=User(id=2, username=Kitty, salary=0, gender=Female)}
Map<String, User> map = stream.collect(Collectors.toMap(User::getId, Function.identity()));
final Stream<User> stream2 = Stream.of(new User("1", "Jerry", "Male"), new User("2", "Kitty", "Female"));
// 将User的ID作为key,username作为value
// 执行结果:mapIdName值为{1=Jerry, 2=Kitty}
Map<String, String> mapIdName = stream2.collect(Collectors.toMap(User::getId, User::getUsername));
如果Collectors.toMap() key值不唯一,给出合并策略
final Stream<User> duplicateKeyStream =
Stream.of(new User("1", "Jerry", "Male"), new User("20", "Jerry", "Female"));
// 下面以username作为key,Stream中存在同名的username "Jerry"。
// 以“后者覆盖前者”的策略解决冲突
// 执行结果:map值为{Jerry=User(id=20, username=Jerry, salary=0, gender=Female)}
Map<String, User> map =
duplicateKeyStream.collect(Collectors.toMap(User::getUsername, Function.identity(), (key1, key2) -> key2));
如果Stream存在null元素,Collectors.toMap()转换失败,建议通过filter()过滤后再进行转换
final Stream<User> nullElementStream = Stream.of(new User("1", "Jerry", "Male"), null);
// 下面代码Stream中存在null元素,Collectors.toMap()将抛出NullPointerException异常
Map<String, String> mapIdName = nullElementStream.collect(Collectors.toMap(User::getId, User::getUsername));
// 过滤出NonNull的元素后进行Map转换,转换后的结果为{1=Jerry}
nullElementStream.filter(Objects::nonNull).collect(Collectors.toMap(User::getId, User::getUsername));
如果Map的value值为null,Collectors.toMap()转换失败,建议通过filter()过滤后再进行转换
final Stream<User> nullValueStream = Stream.of(new User("1", "Jerry", "Male"), new User("2", null));
// 将id、username信息转换为map,由于存在username为null,Collectors.toMap()将抛出NullPointerException异常
Map<String, String> mapIdName = nullValueStream.collect(Collectors.toMap(User::getId, User::getUsername));
// 过滤出Map的value为NonNull的元素后进行Map转换,转换后的结果为{1=Jerry}
nullValueStream.filter(p -> p != null && StringUtils.isNotEmpty(p.getUsername()))
.collect(Collectors.toMap(User::getId, User::getUsername));
8) Stream转换为分组Map
final Stream<User> stream = Stream.of(new User("1", "Jerry", "Male"), new User("2", "Kitty", "Female"));
// 按性别分组,分组结果为
// {Female=[User(id=2, username=Kitty, salary=0, gender=Female)], Male=[User(id=1, username=Jerry, salary=0,
// gender=Male)]}
Map<String, List<User>> group = stream.collect(Collectors.groupingBy(User::getGender));
// Stream实例执行一次终端操作后将不能再次使用,因此,此处创建新的Stream
final Stream<User> stream2 = Stream.of(new User("1", "Jerry", "Male"), new User("2", "Kitty", "Female"));
// 按是否为Female分组,分组结果为
// {false=[User(id=1, username=Jerry, salary=0, gender=Male)], true=[User(id=2, username=Kitty, salary=0,
// gender=Female)]}
Map<Boolean, List<User>> group2 =
stream2.collect(Collectors.partitioningBy(p -> "Female".equalsIgnoreCase(p.getGender())));
4.日期时间 API
java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
import java.time.Month;