-
Lambda表达式:也可以成为闭包,是java8最重要的特性,允许把一个函数作为一个方法的参数,使用它可以使代码变得更加简洁紧凑。
-
Lambda表达式语法
- (parameters) -> expression
- (parameters) -> {expressions;}
-
Lambda表达式特征:
- 可选类型生命:不需要生命参数类型,编译器可以统一识别参数值
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数的时候需要定义圆括号
- 可选的大括号:如果主题包含一个语句,就不需要使用大括号
- 可选的返回值类型:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表明表达式返回了一个数值
-
Lambda表达式演示代码
public class LambdaTest { public static void main(String[] args) { MathOperation mathOperation = () -> 6; System.out.println(mathOperation.print()); MathOperationAdd mathOperationAdd1 = (a, b) -> a + b; MathOperationAdd mathOperationAdd2 = (a, b) -> a * b; System.out.println(mathOperationAdd1.add(2,6)); System.out.println(mathOperationAdd2.add(2,6)); Stringfun stringfun = msg -> System.out.println("msg: "+msg); stringfun.fun("杀猪饭店"); } interface MathOperation{ int print(); } interface MathOperationAdd{ int add(int a, int b); } interface Stringfun{ void fun(String s); } }
-
Lambda表达式变量作用域:只能引用标记了final的外层局部变量,就是说不能在Lambda表达式内部修改定义在域外的局部变量,否则会编译错误,类似于下面的情况
public class LambdaTest2 { public static void main(String[] args) { int num = 1; Convert<Integer, String> s = (param) -> System.out.println(param + num); //num = 1; 会编译报错 s.convert(2); //num = 1; 会编译报错 } public interface Convert<T1, T2>{ void convert(int i); } }
-
Lambda表达式的局部变量可以不声明为final,但必须不可被后面的代码修改(即隐形的具有final的语义)
-
Lambda表达式中不允许声明一个于局部变量同名的参数或者局部变量
import java.util.Comparator; public class LambdaTest3 { public static void main(String[] args) { String first = ""; // Comparator<String> comparator = (first, second) -> 会报错,与上面的first重名 // Integer.compare(first.length(), second.length()); } }
-
方法引用:可以使语言的构造更紧凑、减少冗余代码
-
方法引用使用一堆冒号:: ;
-
方法引用的使用
-
构造器引用:它的语法是Class::new,或者更一般的Class::new,示例如下
final Car car = Car.create(Car::new); final List<Car> cars = Arrays.asList(car);
-
静态方法的引用:它的语法是Class::static_method示例如下
cars.forEach(Car::collid);
-
特定类的任意对象的方法引用:它的语法是Class::method示例如下
cars.forEach(Car::repair):
-
特定对象的方法引用:它的语法是instance::method示例如下
final Car police = Car.create(Car::new); cars.forEach(police::follow);
-
-
方法引用代码示例
import java.util.function.Supplier; public class Car { private String name; private int year; public static Car create(final Supplier<Car> supplier, String name, int year){ name = name; year = year; System.out.println("构造器"); return supplier.get(); } public static void collide(final Car car){ System.out.println("collide被调用了: "+car.toString()); } public void follow(final Car another){ System.out.println("follow the "+another.toString()); } public void repair(){ System.out.println("repaired "+this.toString()); } @Override public String toString() { return "Car{" + "name='" + name + '\'' + ", year=" + year + '}'; } }
import java.util.Arrays; import java.util.List; public class methodTest { public static void main(String[] args) { //构造器引用 Car car = Car.create(Car::new, "BMW", 2); //静态方法引用,语法为 Class::static_method List<Car> cars = Arrays.asList(car); cars.forEach(Car::collide); //特定类任意对象,语法为 Class::method cars.forEach(Car::repair); //特定对象的方法引用,语法为instance::method Car car1 = Car.create(Car::new, "BC", 3); cars.forEach(car1::follow); } }
-
函数式接口:有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
-
函数式接口可以被阴式转为lambda表达式
-
函数式接口代码示例:
@FunctionalInterface public interface CreateFunction { void sayMessage(String message); }
public class FunctionTest { public static void main(String[] args) { CreateFunction createFunction = msg -> System.out.println(msg); createFunction.sayMessage("123123"); } }
-
JDK8新增的函数式接口 java.util.function
序号 接口 & 描述 1 **BiConsumer<T,U>**代表了一个接受两个输入参数的操作,并且不返回任何结果 2 **BiFunction<T,U,R>**代表了一个接受两个输入参数的方法,并且返回一个结果 3 **BinaryOperator**代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果 4 **BiPredicate<T,U>**代表了一个两个参数的boolean值方法 5 BooleanSupplier代表了boolean值结果的提供方 6 **Consumer**代表了接受一个输入参数并且无返回的操作 7 DoubleBinaryOperator代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。 8 DoubleConsumer代表一个接受double值参数的操作,并且不返回结果。 9 **DoubleFunction**代表接受一个double值参数的方法,并且返回结果 10 DoublePredicate代表一个拥有double值参数的boolean值方法 11 DoubleSupplier代表一个double值结构的提供方 12 DoubleToIntFunction接受一个double类型输入,返回一个int类型结果。 13 DoubleToLongFunction接受一个double类型输入,返回一个long类型结果 14 DoubleUnaryOperator接受一个参数同为类型double,返回值类型也为double 。 15 **Function<T,R>**接受一个输入参数,返回一个结果。 16 IntBinaryOperator接受两个参数同为类型int,返回值类型也为int 。 17 IntConsumer接受一个int类型的输入参数,无返回值 。 18 **IntFunction**接受一个int类型输入参数,返回一个结果 。 19 IntPredicate:接受一个int输入参数,返回一个布尔值的结果。 20 IntSupplier无参数,返回一个int类型结果。 21 IntToDoubleFunction接受一个int类型输入,返回一个double类型结果 。 22 IntToLongFunction接受一个int类型输入,返回一个long类型结果。 23 IntUnaryOperator接受一个参数同为类型int,返回值类型也为int 。 24 LongBinaryOperator接受两个参数同为类型long,返回值类型也为long。 25 LongConsumer接受一个long类型的输入参数,无返回值。 26 **LongFunction**接受一个long类型输入参数,返回一个结果。 27 LongPredicateR接受一个long输入参数,返回一个布尔值类型结果。 28 LongSupplier无参数,返回一个结果long类型的值。 29 LongToDoubleFunction接受一个long类型输入,返回一个double类型结果。 30 LongToIntFunction接受一个long类型输入,返回一个int类型结果。 31 LongUnaryOperator接受一个参数同为类型long,返回值类型也为long。 32 **ObjDoubleConsumer**接受一个object类型和一个double类型的输入参数,无返回值。 33 **ObjIntConsumer**接受一个object类型和一个int类型的输入参数,无返回值。 34 **ObjLongConsumer**接受一个object类型和一个long类型的输入参数,无返回值。 35 **Predicate**接受一个输入参数,返回一个布尔值结果。 36 **Supplier**无参数,返回一个结果。 37 **ToDoubleBiFunction<T,U>**接受两个输入参数,返回一个double类型结果 38 **ToDoubleFunction**接受一个输入参数,返回一个double类型结果 39 **ToIntBiFunction<T,U>**接受两个输入参数,返回一个int类型结果。 40 **ToIntFunction**接受一个输入参数,返回一个int类型结果。 41 **ToLongBiFunction<T,U>**接受两个输入参数,返回一个long类型结果。 42 **ToLongFunction**接受一个输入参数,返回一个long类型结果。 43 **UnaryOperator**接受一个参数为类型T,返回值类型也为T。
-
函数式接口实例:
-
Predicate: 接口是一个函数式接口,它接受一个输入参数T,返回一个布尔值。改接口包含多种默认方法来将Predicate组合成其他复杂的逻辑。
该接口用于测试的对象是true或false
-
import java.util.Arrays; import java.util.List; import java.util.function.Predicate; public class PredicateTest { public static void main(String[] args) { /*Predicate<Integer> predicate = n -> n == 2; boolean test = predicate.test(3); System.out.println(test);*/ List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9); Predicate<Integer> predicate = n -> n % 2 == 0; System.out.println("打印偶数"); compare(list, predicate); System.out.println(); System.out.println(); System.out.println("打印大于3的数字"); Predicate<Integer> predicate1 = n -> n > 3; compare(list, predicate1); } private static void compare(List<Integer> list, Predicate<Integer> predicate){ for(Integer i : list){ if(predicate.test(i)){ System.out.println(i + " "); } } } }
-
Function<T, R>,接受一个参数,返回一个结果
import java.util.function.Function; public class FunctionTest { public static void main(String[] args) { Function<String, Boolean> function = s -> null != s; Boolean apply = function.apply(null); System.out.println(apply); Function<Boolean, Integer> functionl2 = s -> s ? 1 : 0; //function的结果作为functionl2的参数 Function<String, Integer> stringIntegerFunction = function.andThen(functionl2); Integer apply1 = stringIntegerFunction.apply(null); System.out.println(apply1); Function<String, Integer> compose = functionl2.compose(function); Integer abs = compose.apply("abs"); System.out.println(abs); } }
-
Consumer接受一个参数,没有返回结果
import java.util.function.Consumer; import static java.lang.System.out; public class ConsumerTest { public static void main(String[] args) { //Consumer<String> consumer = s -> System.out.println(s); Consumer<String> consumer = out::println; consumer.accept("werwer"); } }
-
Supplier接口,不接受参数,只返回一个结果
import java.util.function.Supplier; public class SupplierTest { public static void main(String[] args) { Supplier<String> stringSupplier = () -> "无参数的"; String s = stringSupplier.get(); System.out.println(s); } }
-
默认方法:接口可以有时限方法,而且不需要实现类去实现其方法,只需要在方法名前加一个default关键字,即可实现默认方法
public interface DefaultMethodTest { default void add(int a, int b){ System.out.println(a + b); } }
-
静态默认方法
public interface DefaultMethodTest { static void out(){ System.out.println("吹牛"); } }
-
Optional类:是一个可以为null的容器对象,如果值存在则isPresent()方法返回true,调用get()方法会返回该对象,
-
Optional是个容器,它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显示的进行空值检测。
-
Optional类的引入很好的解决空指针异常。
-
Optional实例:
import java.util.Optional; public class OptionalTest { public static void main(String[] args) { Integer value = 11; //ofNullable允许参数为null Optional<Integer> optional = Optional.ofNullable(value); //of的参数不允许为null //Optional<Integer> optional1 = Optional.of(value); //判断存放的对象是否存在值,是,反回true,不存在则返回false System.out.println(optional.isPresent()); } }
-
Stream:Java8新添加了一个抽象成为Stream,可以让你以一种声明的方式处理数据。
-
Stream使用一种类似用SQL语句从数据库查询数据的直观方式来提供一种对Java集合运算和表达的高阶抽象。
-
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流,流在管道中传输,并且可以在管道的节点上进行处理,比如筛选、排序、聚合等。
-
元素在管道中经过中间操作的处理,最后由最终操作得到前面处理的结果。
-
Stream使用示例
import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class StreamTest { public static void main(String[] args) { List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl"); //利用Stream统计strings中空字符串的个数 long count = strings.stream().filter(s -> s.isEmpty()).count(); System.out.println("count: "+count); //统计Stream中字符串长度为3的个数 long count1 = strings.stream().filter(s -> s.length() == 3).count(); System.out.println("count1: "+count1); //过滤掉空字符串,得到新的列表 List<String> collect = strings.stream().filter(s -> !s.isEmpty()) .collect(Collectors.toList()); System.out.println(collect); //合并字符串,将strings的非空字符串合并为一个新的字符串,中间以逗号隔开 String collect1 = strings.stream().filter(s -> !s.isEmpty()) .collect(Collectors.joining(",")); System.out.println(collect1); } }
-
Stream对数字的操作
import java.util.Arrays; import java.util.IntSummaryStatistics; import java.util.List; import java.util.Random; import java.util.stream.Collectors; public class NumberList { public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7); //获得一个list中各元素平方的新集合 List<Integer> collect = list.stream().map(i -> i * i) .distinct().collect(Collectors.toList()); System.out.println(collect); IntSummaryStatistics intSummaryStatistics = collect.stream() .mapToInt((x) -> x).summaryStatistics(); //获得collect中的最大值 System.out.println(intSummaryStatistics.getMax()); //获得collect中的最小值 System.out.println(intSummaryStatistics.getMin()); //获得collect中的总和 System.out.println(intSummaryStatistics.getSum()); //获得collect中的平均值 System.out.println(intSummaryStatistics.getAverage()); //获取10个随机数 Random random = new Random(); random.ints().limit(10).sorted().forEach(System.out::println); } }
-
日期API
-
旧版的Date的问题
- 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。
- 涉及很差,Java的日期/时间类的定义不一致,在java.util和java.sql的包中都有日期,将其纳入到java.sql的包中并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
- 时区处理麻烦,日期类并不提供国际化,没有时区支持,因此java引入了java.util.Calendar和java.util.timeZone类,但它们同样存在上述的所有问题。
-
Java8在java.time包下提供了很多新的API,
- Local(本地) – 简化了日期时间的处理,没有时区的问题。
- Zoned(时区) – 通过指定的时区处理日期时间
-
新的java.time包涵盖了所有处理日期、时间、日期/时间、时区、时刻(intstants),过程(during)与时钟的(cloak)操作。
-
日期的使用示例
import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; //LocalDate 用于表示当天日期,它只有日期,不包含时间 public class LocalDateTest { public static void main(String[] args) { //获取当前时间 LocalDate now = LocalDate.now(); System.out.println(now); //获取指定日期的日期对象 LocalDate date = LocalDate.of(2000, 1, 1); System.out.println(date); //获取日期对象的年月日数据 int year = now.getYear(); int monthValue = now.getMonthValue(); int dayOfMonth = now.getDayOfMonth(); System.out.println("year: "+year); System.out.println("monthValue: "+monthValue); System.out.println("dayOfMonth: "+dayOfMonth); //比较两个日期是否相等 LocalDate localDate = LocalDate.of(2019, 8, 14); System.out.println(now.equals(localDate)); //日期计算 LocalDate localDate1 = now.plus(1, ChronoUnit.WEEKS); System.out.println(localDate1); //日期的比较 LocalDate localDate2 = LocalDate.of(2000, 1, 1); System.out.println(now.isAfter(localDate2)); LocalDate localDate3 = LocalDate.of(2020, 1, 1); System.out.println(now.isAfter(localDate3)); //时区 ZoneId shanghaiZoneId = ZoneId.of("Asia/Shanghai"); ZonedDateTime now1 = ZonedDateTime.now(shanghaiZoneId); ZoneId tokyoZoneId = ZoneId.of("Asia/Tokyo"); ZonedDateTime now2 = ZonedDateTime.now(tokyoZoneId); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); System.out.println("上海时间为: " + now1.format(formatter)); System.out.println("东京时间为: " + now2.format(formatter)); //解析日期 String dateText = "20190813"; LocalDate date2 = LocalDate.parse(dateText, DateTimeFormatter.BASIC_ISO_DATE); System.out.println(date2); //格式化日期 String format = now.format(DateTimeFormatter.ISO_DATE); System.out.println(format); //日期转换字符串 LocalDateTime localDateTime = LocalDateTime.now(); DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); String format1 = localDateTime.format(formatter1); System.out.println(format1); //字符串转时间 String dateTimeText = "2018-08-14 10:25:26"; LocalDateTime dateTime = LocalDateTime.parse(dateTimeText, formatter1); System.out.println(dateTime); } }
-
时间的使用示例
import java.time.LocalTime; //LocalTime 用于表示当天时间, 它只有时间,不包含日期。 public class LocalTimeTest { public static void main(String[] args) { LocalTime now = LocalTime.now(); System.out.println(now); LocalTime localTime = now.plusHours(2); System.out.println(localTime); } }
Java8新特性
最新推荐文章于 2023-05-23 23:21:12 发布