Java8新特性总结
Java8是大部分公司使用的一个版本,我们来学习总结一下新特性吧。
接口相关
- 可以使用static关键字。让接口的方法成为该接口的私有方法,无法被继承,只能通过接口调用。
- 可以使用default关键字。让接口可以被继承,重写,但是也可以选择不重写,从而使用默认的方式。
public interface Food {
void eat();
//无法被继承
static void hello() {
System.out.println("hello world!");
}
//可以继承,也可以不继承,然后使用默认的方法
default void say() {
System.out.println("这是default");
}
}
public class Test implements Food {
@Override
public void eat() {
System.out.println("eat");
}
public static void main(String[] args) {
Food.hello();
Test test = new Test();
test.eat();
test.say();
}
}
结果
hello world!
eat
这是default
Lambda表达式
提供函数式编程,格式为(parameters) -> expression
//Java8之前的排序方式
List<Integer> list = Arrays.asList(3, 2, 1, 6);
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
//lambda表达式实现上述排序
Collections.sort(list, (o1, o2) -> (o1 - o2));
//可以使用外部变量,但是不允许修改,默认拥有final属性
int k=1;
Collections.sort(list,(o1,o2)->(o1-k));
// 还可以进一步优化
list.sort((o1, o2) -> o1 - o2);
forEach
List<String> list = Arrays.asList("1", "2", "3");
//java8之前
for (String s : list) {
System.out.println(s);
}
//forEach,使用lambda表达式
list.forEach((s) -> System.out.println(s));
::
传递方法或者构造函数引用
List<String> list = Arrays.asList("1", "2", "3");
//java8之前
for (String s : list) {
System.out.println(s);
}
//forEach,下面用了::
list.forEach(System.out::println);
Stream
把数据想象成水管里的水流,Java流就是对这些水流进行处理,包括筛选、排序、统计、计数等。
Stream 操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回 Stream 本身,这样你就可以将多个操作依次串起来
public class Main {
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
stringList.add("ddd2");
stringList.add("aaa2");
stringList.add("bbb1");
stringList.add("aaa1");
stringList.add("bbb3");
stringList.add("ccc");
stringList.add("bbb2");
stringList.add("ddd1");
// 中间操作 过滤
stringList.stream().filter((s) -> s.startsWith("a")).forEach(System.out::println);
// 中间操作 排序
stringList.stream().sorted().filter((s) -> s.startsWith("a")).forEach(System.out::println);
// 中间操作 映射
stringList.stream().map(String::toUpperCase).sorted((a, b) -> b.compareTo(a)).forEach(System.out::println);
// 最终操作 匹配
boolean anyStartsWithA = stringList.stream().anyMatch((s) -> s.startsWith("a"));
System.out.println(anyStartsWithA);
boolean allStartsWithA = stringList.stream().allMatch((s) -> s.startsWith("a"));
System.out.println(allStartsWithA);
boolean noneStartsWithZ = stringList.stream().noneMatch((s) -> s.startsWith("z"));
System.out.println(noneStartsWithZ);
// 最终操作 计数
long startsWithB = stringList.stream().filter((s) -> s.startsWith("b")).count();
System.out.println(startsWithB);
// 最终操作 规约
Optional<String> reduced = stringList.stream().sorted().reduce((s1, s2) -> s1 + "#" + s2);
reduced.ifPresent(System.out::println);
// 并行流
int max = 1000000;
List<String> values = new ArrayList<>(max);
for (int i = 0; i < max; i++) {
UUID uuid = UUID.randomUUID();
values.add(uuid.toString());
}
//并行排序
long s0 = System.nanoTime();
values.parallelStream().sorted();
long s1 = System.nanoTime();
long millis1 = TimeUnit.NANOSECONDS.toMillis(s1 - s0);
System.out.println(String.format("parallel sort took: %d ms", millis1));
}
}
Optional
为了解决NullPointException问题。
传统的解决方法是调用前判断是否为空再调用。
class Zoo{
private Dog dog;
}
class Dog{
private int age;
}
Zoo zoo=getZoo();
if(!zoo=null){
Dog dog=zoo.getDog();
if(dog!=null){
int age=dog.getAge();
//do something
}
}
//Optional则是这么实现的
Optional.ofNullable(zoo).map(o->o.getDog()).map(d->d.getAge()).ifPrensent(age->//do something)
其他例子
public class Main {
public static void main(String[] args) {
// of():为非null的值创建一个Optional
Optional<String> optional = Optional.of("bam");
// isPresent():如果值存在返回true,否则返回false
// true
System.out.println(optional.isPresent());
// get():如果Optional有值则将其返回,否则抛出NoSuchElementException
// bam
System.out.println(optional.get());
// orElse():如果有值则将其返回,否则返回指定的其它值
// bam
System.out.println(optional.orElse("fallback"));
// ifPresent():如果Optional实例有值则为其调用consumer,否则不做处理
// b
optional.ifPresent((s) -> System.out.println(s.charAt(0)));
}
}
Time类
Java.time包括了LocalDateTime,LocalDate,LocalTime
Clock
public class Main {
public static void main(String[] args) {
Clock clock = Clock.systemDefaultZone();
long millis = clock.millis();
System.out.println(millis);
Instant instant = clock.instant();
System.out.println(instant);
Date legacyDate = Date.from(instant);
System.out.println(legacyDate);
}
}
Timezones
public class Main {
public static void main(String[] args) {
System.out.println(ZoneId.getAvailableZoneIds());
ZoneId zone1 = ZoneId.of("Europe/Berlin");
ZoneId zone2 = ZoneId.of("Brazil/East");
System.out.println(zone1.getRules());
System.out.println(zone2.getRules());
}
}
LocalTime
LocalTime 定义了一个没有时区信息的时间
public class Main {
public static void main(String[] args) {
ZoneId zone1 = ZoneId.of("Europe/Berlin");
ZoneId zone2 = ZoneId.of("Brazil/East");
LocalTime now1 = LocalTime.now(zone1);
LocalTime now2 = LocalTime.now(zone2);
System.out.println(now1.isBefore(now2));
long hoursBetween = ChronoUnit.HOURS.between(now1, now2);
long minutesBetween = ChronoUnit.MINUTES.between(now1, now2);
System.out.println(hoursBetween);
System.out.println(minutesBetween);
}
}
LocalTime 提供了多种工厂方法来简化对象的创建,包括解析时间字符串
public class Main {
public static void main(String[] args) {
LocalTime late = LocalTime.of(23, 59, 59);
System.out.println(late);
DateTimeFormatter germanFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).withLocale(Locale.GERMAN);
LocalTime leetTime = LocalTime.parse("13:37", germanFormatter);
System.out.println(leetTime);
}
}
LocalDate
public class Main {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
System.out.println("今天的日期: " + today);
LocalDate tomorrow = today.plus(1, ChronoUnit.DAYS);
System.out.println("明天的日期: " + tomorrow);
LocalDate yesterday = tomorrow.minusDays(2);
System.out.println("昨天的日期: " + yesterday);
LocalDate independenceDay = LocalDate.of(2019, Month.MARCH, 12);
DayOfWeek dayOfWeek = independenceDay.getDayOfWeek();
System.out.println("今天是周几:" + dayOfWeek);
}
}
LocalDateTime
public class Main {
public static void main(String[] args) {
LocalDateTime sylvester = LocalDateTime.of(2014, Month.DECEMBER, 31, 23, 59, 59);
DayOfWeek dayOfWeek = sylvester.getDayOfWeek();
System.out.println(dayOfWeek);
Month month = sylvester.getMonth();
System.out.println(month);
long minuteOfDay = sylvester.getLong(ChronoField.MINUTE_OF_DAY);
System.out.println(minuteOfDay);
}
}
内置函数式接口
Predicate
判断一个参数是否符合要求
Predicate<String> predicate = s -> s.length() > 0;
// true
System.out.println(predicate.test("test"));
// false
System.out.println(predicate.negate().test("foo"));
Function
接受参数并生成结果,可用于将多个函数连接在一起。
Function<String, Integer> toInteger = Integer::valueOf;
Function<String, String> backToString = toInteger.andThen(String::valueOf);
System.out.println(backToString.apply("123"));
Supplier
产生给定泛型类型的结果
public class People {
void hello() {
System.out.println("hello");
}
}
public class Main {
public static void main(String[] args) {
Supplier<People> personSupplier = People::new;
personSupplier.get().hello();
}
}
Consumer
消费某个对象
public class Main {
public static void main(String[] args) {
Consumer<Integer> square = x -> System.out.println("平方计算 : " + x * x);
square.accept(2);
//当前值
Consumer<Integer> consumer1 = x -> System.out.println("当前值 : " + x);
//相加
Consumer<Integer> consumer2 = x -> {
System.out.println("相加 : " + (x + x));
};
//相乘
Consumer<Integer> consumer3 = x -> System.out.println("相乘 : " + x * x);
//andThen拼接
consumer1.andThen(consumer2).andThen(consumer3).accept(1);
//可以用于变量list赋值
List<People> list = new ArrayList<>();
list.add(new People("xiaoming"));
list.add(new People("xiahong"));
list.forEach(o -> o.setName("hello"));
}
}