java8新特性总结备忘
List<String> list = Arrays.asList("a", "b", "d", "c");
//一个lambda可以由用逗号分隔的参数列表、–>符号与函数体三部分表示
list.forEach(e -> System.out.println(e));
list.forEach((String e) -> System.out.println(e));
// 在某些情况下lambda的函数体会更加复杂,这时可以把函数体放到在一对花括号中
list.forEach(e -> {
System.out.println(e);
System.out.println(e + "xxx");
});
//Lambda可能会返回一个值。返回值的类型也是由编译器推测出来的。
// 如果lambda的函数体只有一行的话,那么没有必要显式使用return语句
list.sort((e1, e2) -> e1.compareTo(e2));
System.out.println(list);
list.sort((e1, e2) -> {
int res = e1.compareTo(e2);
return res;
});
/**
* 默认方法与抽象方法不同之处在于抽象方法必须要求实现,
* 但是默认方法则没有这个要求。相反,每个接口都必须提供一个所谓的默认实现,
* 这样所有的接口实现者将会默认继承它(如果有必要的话,可以覆盖这个默认实现)
*
* @author: EarthChen
* @date: 2018/05/06
*/
public interface Defaulable {
default String notRequired() {
return "Default implementation";
}
}
不覆盖默认方法,让默认方法保持原样
/**
* 实现了接口,并且让默认方法保持原样
*
* @author: EarthChen
* @date: 2018/05/06
*/
public class DefaultableImpl implements Defaulable {
}
覆盖默认方法
/**
* 实现了接口,并且覆盖了默认方法
*
* @author: EarthChen
* @date: 2018/05/06
*/
public class OverridableImpl implements Defaulable {
@Override
public String notRequired() {
return "Overridden implementation";
}
}
接口还可以声明(并且可以提供实现)静态方法
/**
* 可以声明(并且可以提供实现)静态方法
*
* @author: EarthChen
* @date: 2018/05/06
*/
public interface DefaulableFactory {
static Defaulable create(Supplier<Defaulable> supplier) {
return supplier.get();
}
}
首先定义一个Car类作为例子
public class Car {
public static Car create(final Supplier<Car> supplier) {
return supplier.get();
}
public static void collide(final Car car) {
System.out.println("Collided " + car.toString());
}
public void follow(final Car another) {
System.out.println("Following the " + another.toString());
}
public void repair() {
System.out.println("Repaired " + this.toString());
}
}
各种引用的例子
//引用是构造器引用,它的语法是Class::new,或者更一般的Class< T >::new。请注意构造器没有参数。
Car car = Car.create(Car::new);
List<Car> cars = Arrays.asList(car);
//静态方法引用,它的语法是Class::static_method。请注意这个方法接受一个Car类型的参数。
cars.forEach(Car::collide);
//引用是特定类的任意对象的方法引用,它的语法是Class::method。请注意,这个方法没有参数。
cars.forEach(Car::repair);
//引用是特定对象的方法引用,它的语法是instance::method。请注意,这个方法接受一个Car类型的参数
Car police = Car.create(Car::new);
cars.forEach(police::follow);
首先构造一个结构作为我们使用stream的例子
public enum Status {
OPEN,
CLOSED
}
/**
* Task类有一个分数的概念(或者说是伪复杂度),其次是还有一个值可以为OPEN或CLOSED的状态
*
* @author: EarthChen
* @date: 2018/05/06
*/
public class Task {
private final Status status;
private final Integer points;
Task(final Status status, final Integer points) {
this.status = status;
this.points = points;
}
public Integer getPoints() {
return points;
}
public Status getStatus() {
return status;
}
@Override
public String toString() {
return String.format("[%s, %d]", status, points);
}
}
使用的例子
Collection<Task> tasks = Arrays.asList(
new Task(Status.OPEN, 5),
new Task(Status.OPEN, 13),
new Task(Status.CLOSED, 8));
//所有状态为OPEN的任务一共有多少分数
long totalPointsOfOpenTasks = tasks.stream()
.filter(task -> task.getStatus() == Status.OPEN)
.mapToInt(Task::getPoints)
.sum();
System.out.println("Total points: " + totalPointsOfOpenTasks);
//能够原生支持并行处理。让我们来看看这个算task分数和的例子。
double totalPoints = tasks.parallelStream()
.map(Task::getPoints)
.reduce(0, Integer::sum);
System.out.println("Total points (all tasks): " + totalPoints);
//需要按照某种准则来对集合中的元素进行分组
Map<Status, List<Task>> map = tasks.stream()
.collect(Collectors.groupingBy(Task::getStatus));
System.out.println(map);
//整个集合中每个task分数(或权重)的平均值
Collection<String> res = tasks.stream()
.mapToInt(Task::getPoints)
.asLongStream()
.mapToDouble(points -> points / totalPoints)
.boxed()
.mapToLong(weigth -> (long) (weigth * 100))
.mapToObj(percentage -> percentage + "%")
.collect(Collectors.toList());
System.out.println(res);
String filename = "";
Path path = new File(filename).toPath();
try (Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8)) {
lines.onClose(() -> System.out.println("Done!")).forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
//是Clock类,它通过指定一个时区,然后就可以获取到当前的时刻,日期与时间。
// Clock可以替换System.currentTimeMillis()与TimeZone.getDefault()。
Clock clock = Clock.systemUTC();
System.out.println(clock.instant());
System.out.println(clock.millis());
//LocaleDate只持有ISO-8601格式且无时区信息的日期部分
LocalDate date = LocalDate.now();
LocalDate dateFromClock = LocalDate.now(clock);
System.out.println(date);
System.out.println(dateFromClock);
//LocaleTime只持有ISO-8601格式且无时区信息的时间部分
LocalTime time = LocalTime.now();
LocalTime timeFromClock = LocalTime.now(clock);
System.out.println(time);
System.out.println(timeFromClock);
//LocaleDateTime把LocaleDate与LocaleTime的功能合并起来,
// 它持有的是ISO-8601格式无时区信息的日期与时间
LocalDateTime datetime = LocalDateTime.now();
LocalDateTime datetimeFromClock = LocalDateTime.now(clock);
System.out.println(datetime);
System.out.println(datetimeFromClock);
//如果你需要特定时区的日期/时间,那么ZonedDateTime是你的选择。
// 它持有ISO-8601格式具具有时区信息的日期与时间
ZonedDateTime zonedDatetime = ZonedDateTime.now();
ZonedDateTime zonedDatetimeFromClock = ZonedDateTime.now(clock);
ZonedDateTime zonedDatetimeFromZone = ZonedDateTime.now(ZoneId.of("America/Los_Angeles"));
System.out.println(zonedDatetime);
System.out.println(zonedDatetimeFromClock);
System.out.println(zonedDatetimeFromZone);
//Duration类:在秒与纳秒级别上的一段时间。Duration使计算两个日期间的不同变的十分简单
LocalDateTime from = LocalDateTime.of(2014, Month.APRIL, 16, 0, 0, 0);
LocalDateTime to = LocalDateTime.of(2015, Month.APRIL, 16, 23, 59, 59);
Duration duration = Duration.between(from, to);
System.out.println("Duration in days: " + duration.toDays());
System.out.println("Duration in hours: " + duration.toHours());
long[] arrayOfLong = new long[20000];
//对一个有20000个元素的数组进行随机赋值
Arrays.parallelSetAll(arrayOfLong,
index -> ThreadLocalRandom.current().nextInt(1000000));
//打印出前10个元素的值
Arrays.stream(arrayOfLong).limit(10).forEach(
i -> System.out.print(i + " "));
System.out.println();
//并行排序
Arrays.parallelSort(arrayOfLong);
//打印出前10个元素的值
Arrays.stream(arrayOfLong).limit(10).forEach(
i -> System.out.print(i + " "));
System.out.println();
还有一些特性这里不做总结,以上只举例一些常用的特性
参考: