参数列表
箭头
Lambda主体
比如:
(String s) -> s.length()
使用lambda表达式要满足函数式接口。
函数式接口,就是只定义了一个抽象方法的接口。
public interface Predicate<T> {
boolean test(T t);
}
这个接口的意思是接收一个泛型对象T,返回true或者false。
用实现这个接口的方式来表达类似于:
public class MyObj implements Predicate<T> {
public boolean test (T t) {
// 代码执行逻辑...
return true // 函数一个返回 true 或者 false
}
}
public interface Compartor<T> {
int compare(T o1, T o2);
}
public interface Runnable {
public abstract void run();
}
public interface Callable<V> {
V call() throw Exception;
}
public interface Runnable {
public abstract void run();
}
写成Lambda表达式后的接口为:
Runnable r = () -> System.out.println("hello lambda!");
r.run();
等同于:
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("hello lambda!");
}
};
r1.run();
public class Main {
public static void main(String[] args) {
// 获取数组中所有偶数
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8};
// 参数传递一个lambda表达式 相当于一个匿名实现类 但是这个实现类只有一个抽象函数
// 否则这个方法体不知道给那个要实现的方法...
List<Integer> evenNumber = getEvenNumber(arr, (Integer i) -> i % 2 == 0);
System.out.println(evenNumber);
}
// 参数是一个接口
public static List<Integer> getEvenNumber(int[] arrs , Predicate<Integer> p) {
List<Integer> result = new ArrayList<>();
for (int i = 0; i < arrs.length; i++) {
if (p.test(arrs[i])) {
result.add(arrs[i]);
}
}
return result;
}
}
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
示例:
public class Java8 {
@Test
public void testPredicate() {
List<Integer> array = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
List<Integer> filter = filter(array, (Integer i) -> i >= 4);
System.out.println(filter);
}
public static <T> List<T> filter(List<T> arr, Predicate<T> p) {
List<T> list = new ArrayList<T>();
for (T t: arr) {
if (p.test(t)) {
list.add(t);
}
}
return list;
}
}
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
示例:
@Test
public void testConsumer() {
Consumer<String> consumer = (String s) -> System.out.println(s);
accept("hello java 8", consumer);
}
public static void accept(String msg, Consumer<String> consumer) {
consumer.accept(msg);
}
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
示例:
@Test
public void testFunction() {
Function<Integer, String> fn = (Integer i) -> "hello " + i;
String apply = apply(fn);
System.out.println(apply);
}
public static String apply(Function<Integer, String> fn) {
return fn.apply(12);
}
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
*/
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
@FunctionalInterface
public interface Supplier<T> {
T get();
}
T apply(T t);
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
}
T apply(T t, T u);
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
}
@FunctionalInterface
public interface BiPredicate<T, U> {
boolean test(T t, U u);
}
@FunctionalInterface
public interface BiConsumer<T, U> {
void accept(T t, U u);
}
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u);
}
在Lambda表达式中访问外部变量,**外部变量(这里指的是局部变量)**应该是不能改变的,或者说是final的,比如:
这个是正确的:
@Test
public void testVariable() {
int i = 10;
Runnable rn = () -> System.out.println(i);
}
这个是错误的,因为改变了变量i的值:
@Test
public void testVariable() {
int i = 10;
Runnable rn = () -> System.out.println(i);
i = 20;
}
原因:原来的线程局部变量i,i使用完后可能会被回收,Lambda是在另一个线程中的,访问的是i的副本,所以i不应该改变。
排序的例子:
@Test
public void testMethod() {
List<Apple> apples = new ArrayList();
apples.add(new Apple("red", 10));
apples.add(new Apple("red", 20));
apples.add(new Apple("red", 30));
apples.add(new Apple("red", 40));
// 方式1
apples.sort((a, b) -> a.getWeight().compareTo(b.getWeight()));
// 方式2
apples.sort(comparing((Apple a) -> a.getWeight()));
// 方式3
apples.sort(comparing(Apple::getWeight));
}
例子中的方法引用:
(Apple a) -> a.getWeight()
的方法引用就是:Apple::getWeight
。
@Test
public void testSupplier() {
// 调用无参构造函数
Supplier<Apple> appleSupplier = Apple::new;
Apple apple = appleSupplier.get();
System.out.println(apple);
// 调用构造函数是 Integer的那个
Function<Integer, Apple> appleFunction = Apple::new;
Apple apply = appleFunction.apply(100);
System.out.println(apply);
}
Supplier
等价于Supplier
Function
等价于Function
@Test
public void testSupplier() {
// 调用无参构造函数
Supplier<Apple> appleSupplier = Apple::new;
Apple apple = appleSupplier.get();
// 等价于
Supplier<Apple> a = new Supplier() {
@Override
public Object get() {
return new Apple();
}
};
// 调用构造函数是 Integer的那个
Function<Integer, Apple> appleFunction = Apple::new;
Apple apply = appleFunction.apply(100);
// 等价于
Function<Integer, Apple> f = new Function<Integer, Apple>() {
@Override
public Apple apply(Integer integer) {
return new Apple(integer);
}
};
}
应用示例:
@Test
public void test() {
List<Integer> weight = Arrays.asList(10, 20, 30, 40, 50);
List<Apple> apple = createApple(weight, Apple::new);
System.out.println(apple);
}
public static List<Apple> createApple(List<Integer> weight, Function<Integer, Apple> fn) {
List<Apple> apples = new ArrayList<>();
for (Integer i: weight) {
apples.add(fn.apply(i));
}
return apples;
}
两个构造函数:
@Test
public void twoParametersConstructor() {
BiFunction<String, Integer, Apple> appleBiFunction = Apple::new;
Apple redApple = appleBiFunction.apply("red", 10);
System.out.println(redApple);
// 等价于
BiFunction<String, Integer, Apple> appleBiFunction1 = new BiFunction<String, Integer, Apple>() {
@Override
public Apple apply(String s, Integer integer) {
return new Apple(s, integer);
}
};
Apple greenApple = appleBiFunction1.apply("green", 30);
System.out.println(greenApple);
}
public interface InterfaceApple<T, U, V, R> {
// 三个参数的构造函数
R apply(T t, U u, V v);
}
应用:
@Test
public void threeParametersConstructor() {
InterfaceApple<String, Integer, String, Apple> apple = Apple::new;
Apple apply = apple.apply("red", 10, "green apple");
System.out.println(apply);
}
@Test
public void testStream1() {
List<String> strs = Arrays.asList("java", "in", "action");
Stream<String> stream = strs.stream();
stream.forEach(System.out::println);
}
流只能被操作一次,操作完后流就被关闭了。
@Test
public void testStream1() {
List<String> strs = Arrays.asList("java", "in", "action");
Stream<String> stream = strs.stream();
stream.forEach(System.out::println);
// 这里两次操作这个流就会报错
stream.forEach(System.out::println);
}
一个流执行一个方法返回一个新流的操作是中间操作,如果返回一个不是一个流的值或者void,那么这个方法就是终端操作。例如:
@Test
public void testStream1() {
List<String> strs = Arrays.asList("java", "in", "action");
Stream<String> stream = strs.stream();
stream.filter(s -> s.length() > 3).forEach(System.out::println);
}
上面的filter方法执行后返回的就是一个stream流,这就是一个中间操作,而forEach返回的是void而不是一个新流,这就是一个终端操作。
filter方法,接收一人Predicate接口子类,返回一个满足条件的新流。
@Test
public void filter() {
List<Dish> list = menu.stream()
// 接收一个Predicate,接收一个boolean类型
.filter(d -> d.getCalories() > 400)
.collect(Collectors.toList());
System.out.println(list);
}
distinct会根据元素的hashCode和equalse方法返回一个新流。
@Test
public void distinct() {
List<Integer> numbers = Arrays.asList(1, 2, 1, 4, 2, 6, 4, 8);
List<Integer> list = numbers.stream()
// 去重,通过比较equals和hashCode方法
.distinct()
.collect(Collectors.toList());
System.out.println(list);
}
limit方法接收一个long类型数值,从前向后截断指定个数的元素并,并返回对应的一个新流。
@Test
public void limit() {
List<Integer> numbers = Arrays.asList(1, 2, 1, 4, 2, 6, 4, 8);
List<Integer> list = numbers.stream()
// 截断,接收一个long类型的长度
.limit(2)
.collect(Collectors.toList());
System.out.println(list);
}
与limit方法相反,skip方法接收一个long类型参数,表示跳过前面指定数值的元素,保留后面的元素。
@Test
public void skip() {
List<Integer> numbers = Arrays.asList(1, 2, 1, 4, 2, 6, 4, 8);
List<Integer> list = numbers.stream()
// 跳过前两个元素
.skip(2)
.collect(Collectors.toList());
System.out.println(list);
}
map方法可以映射生成一个新的流,.map(Dish::getName)
就是生成一个以name为值的新流,.map(String::length)
把name为值的新流生成一个name的长度的新流。
@Test
public void map() {
List<Integer> collect = menu.stream()
.map(Dish::getName)
.map(String::length)
.collect(Collectors.toList());
System.out.println(collect);
}
.map(d -> d.split(""))
把字符串分割成了两数组,.flatMap(Arrays::stream)
把每个流中的每个元素分别映射成一个流。然后把所有的流连接起来成为一个流。
@Test
public void flatMap() {
String[] strs = {"hello", "world"};
List<String> collect = Arrays.stream(strs)
.map(d -> d.split(""))
.flatMap(Arrays::stream)
.distinct()
.collect(Collectors.toList());
System.out.println(collect); // [h, e, l, o, w, r, d]
}
感受下面的例子:
@Test
public void testFlatmap() {
List<Integer> ints1 = Arrays.asList(1, 2, 3);
List<Integer> ints2 = Arrays.asList(3, 4);
List<int[]> collect = ints1.stream()
.flatMap(d ->
ints2.stream().
map(j -> new int[]{d, j})
)
.collect(Collectors.toList());
}
.flatMap(d ->ints2.stream().map(j -> new int[]{d, j}) )
中d ->ints2.stream().map(j -> new int[]{d, j})
会生成3个流,这三个流会被flatMap合并成一个流,这个流再被.collect(Collectors.toList());
转换成list。
查找是否有一个匹配,返回值是一个boolean类型
@Test
public void anyMatch() {
// 只要有一个对象的d.getCalories()大于400,就返回true
boolean b = menu.stream().anyMatch(d -> d.getCalories() > 400);
}
查找是否全部匹配
@Test
public void allMatch() {
// 只有全部大于400 才返回true
boolean b = menu.stream().allMatch(d -> d.getCalories() > 400);
System.out.println(b);
}
查找是否没有匹配的
@Test
public void noneMatch() {
// 没有大于4000的就返回true
boolean b = menu.stream().noneMatch(d -> d.getCalories() > 4000);
System.out.println(b);
}
返回任一元素
@Test
public void findAny() {
// findAny 返回流中的元素,返回类型是Optional容器类
List<Integer> numbers = Arrays.asList(2, 3, 4, 5, 6, 7);
Optional<Integer> any = numbers.stream().findAny();
}
查找第一个元素
@Test
public void findFirst() {
// 查找第一个元素
List<Integer> numbers = Arrays.asList(2, 3, 4, 5, 6, 7);
Optional<Integer> first = numbers.stream().findFirst();
// 如果 Optional 中在就执行
first.ifPresent(System.out::println);
}
@Test
public void reduce() {
List<Integer> numbers = Arrays.asList(2, 3, 4, 5, 6);
Integer reduce = numbers.stream()
// 第一个参数 0 是初始值 依次执行0+2=2 2+3=5 5+4=9 9+5=14 14+6=20,也即a依次为0,2,5,9,14
.reduce(0, (a, b) -> a + b);
// 直接使用Integer的sum方法
reduce = numbers.stream().reduce(0, Integer::sum);
System.out.println(reduce);
}
如果不指定初始值返回Optional对象Optional
用来计算最小值:
numbers.stream().reduce(Integer::min);
数值流:IntStream、DoubleStream、LongStream,与Stream
@Test
public void test() {
// Stream
Stream<Integer> integerStream = ps.stream().map(P::getNumber);
// IntStream
IntStream intStream = ps.stream().mapToInt(P::getNumber);
// Stream 与 IntStream 相比 少了自动拆箱的过程,提高了效率
}
求和:
@Test
public void test() {
// IntStream
IntStream intStream = ps.stream().mapToInt(P::getNumber);
// Stream 与 IntStream 相比 少了自动拆箱的过程,提高了效率
int sum = intStream.sum();
System.out.println(sum);
}
数值流转换成普通流boxed:
@Test
public void test() {
IntStream intStream = ps.stream().mapToInt(P::getNumber);
Stream<Integer> boxed = intStream.boxed();
}
求最大值操作:
@Test
public void test() {
IntStream intStream = ps.stream().mapToInt(P::getNumber);
// 获取最大值
OptionalInt max = intStream.max();
// 如果存在 就是最大值 否则就是 30
int i = max.orElse(30);
System.out.println(i);
}
通过Stream.of接收一组数据创建流。
@Test
public void streamOf() {
Stream<String> a = Stream.of("a", "ab", "abc", "abcd");
a.map(String::toUpperCase).forEach(System.out::println);
}
通过Arrays.stream接收一个数组创建流。
@Test
public void arraysStream() {
int[] a = new int[] {1, 2, 3, 4, 6};
IntStream stream = Arrays.stream(a);
stream.forEach(System.out::println);
}
Stream.iterate生成无限流:
@Test
public void streamIterate() {
Stream.iterate(0, n -> n + 2)
.limit(3)
.forEach(System.out::println);
}
Stream.generate生成无限流:
@Test
public void streamGenerate() {
Stream.generate(() -> 1).limit(5).forEach(System.out::println);
}
Collectors提供了很多工厂方法
@Test
public void collectors() {
Long collect = menu.stream().collect(Collectors.counting());
long count = menu.stream().count();
}
@Test
public void minOrMax() {
Comparator<Dish> comparing = comparing(Dish::getCalories);
Optional<Dish> collect = menu.stream().collect(Collectors.maxBy(comparing));
Optional<Dish> collect1 = menu.stream().collect(Collectors.minBy(comparing));
collect.ifPresent(System.out::println);
}
@Test
public void summingInt() {
Integer collect = menu.stream().collect(Collectors.summingInt(Dish::getCalories));
System.out.println(collect);
}
@Test
public void average() {
Double collect = menu.stream().collect(Collectors.averagingInt(Dish::getCalories));
System.out.println(collect);
}
@Test
public void summarizing() {
IntSummaryStatistics collect = menu.stream().collect(Collectors.summarizingInt(Dish::getCalories));
double average = collect.getAverage();
int max = collect.getMax();
int min = collect.getMin();
long sum = collect.getSum();
}
@Test
public void joining() {
String collect = menu.stream().map(Dish::getName).collect(Collectors.joining());
// 使用分割符
String collect1 = menu.stream().map(Dish::getName).collect(Collectors.joining(","));
System.out.println(collect);
System.out.println(collect1);
}
@Test
public void collectReduce() {
menu.stream().collect(Collectors.reducing(0, Dish::getCalories, (i, j) -> i + j));
}
@Test
public void groupingBy() {
Map<Dish.Type, List<Dish>> collect = menu.stream().collect(Collectors.groupingBy(Dish::getType));
System.out.println(collect);
}
自定义分组:
@Test
public void groupingBy1() {
Map<String, List<Dish>> collect = menu.stream().collect(Collectors.groupingBy(dish -> {
if (dish.getCalories() > 400) return "123";
else if (dish.getCalories() > 800) return "456";
else return "789";
}));
System.out.println(collect);
}
多级分组:
@Test
public void groupingBy2() {
Map<Integer, Map<String, List<Dish>>> collect = menu.stream().collect(Collectors.groupingBy(Dish::getCalories, Collectors.groupingBy(dish -> {
if (dish.getCalories() > 400) return "123";
else if (dish.getCalories() > 800) return "456";
else return "789";
})));
System.out.println(collect);
}
分组第二个参数:
@Test
public void groupingBy3() {
Map<Dish.Type, Long> collect = menu.stream()
.collect(Collectors.groupingBy(Dish::getType, Collectors.counting()));
System.out.println(collect); // {FISH=2, MEAT=3, OTHER=4}
}
Collectors.partitioningBy接收boolean值,通过属性的true和false来筛选:
@Test
public void partitioningBy() {
Map<Boolean, List<Dish>> collect = menu.stream().collect(Collectors.partitioningBy(Dish::isVegetarian));
System.out.println(collect);
}
1.在接口中的静态方法和类中的静态方法一样是可以通过接口名直接调用的。
2.实现类实现了接口,实现类不能调用静态方法。(类的继承,子类是可以调用父类中的静态方法的,接口继承也不能调用 )
如果一个接口确定被许多实现者实现了,然后这个接口需要添加新的方法,那么所有实现了这个接口的类都要为其添加一个新的方法的实现。default可以在接口中添加一个有方法体的方法,而且实现类不需要实现这个方法。
// 创建一个空的Optional对象
Optional<Person> person = Optional.empty();
要注意的是如果of()方法接收的对象是一个 null值,程序会报错。
// 创建一个非null的Optional
Person p = new Person();
p.setUsername("tom");
p.setAge(10);
Optional<Person> person = Optional.of(p);
通过of()方法创建的Optional对象如果接收的是一个null值是会报错的,如果要接收一个为null的对象,可以用方法ofNullable()方法。这个方法的意思是可以接收一个为null的对象,当然也可以接收一个对象不为null。
// 创建一个可以为Null的Optional对象
Person p = null;
Optional<Person> person = Optional.ofNullable(p);
map方法,可以用来获取一次对象。
Person p = new Person();
p.setAge(10);
p.setUsername("Tom");
Address address = new Address();
City city1 = new City();
city1.setName("sz");
address.setCity(city1);
p.setAddress(address);
Optional<Person> p1 = Optional.of(p);
// 从Optional中获取对象
Optional<City> city = p1.map(x -> p.getAddress()).map(a -> a.getCity());
// 检查是否存在
System.out.println(city.isPresent());
Optional可以作与Stream类似的操作,例如map(),flatMap,filter等。
OptionalInt、OptionalDouble、OptionalLong、OptionalBoolean,但是基础类Optional不支持map等操作。
LocalDate:操作日期API
LocalTime:操作时间API
Instant:
Duration:
Period:
创建日期对象以及获取日期信息:
// 生成指定时间的日期对象
LocalDate time = LocalDate.of(2018, 12, 3);
// 生成当前日期对象
LocalDate now = LocalDate.now();
// 从LocalDate中获取时间信息
time.getDayOfMonth();
time.getYear();
time.getMonth();
time.getDayOfWeek();
time.getDayOfYear();
time.lengthOfMonth();
time.lengthOfYear();
通过public int get(TemporalField field)
获取日期信息:
time.get(ChronoField.DAY_OF_MONTH);
time.get(ChronoField.DAY_OF_YEAR);
字符串转换为日期:
LocalDate parse = LocalDate.parse("2018-10-20");
// 生成时间
LocalTime time = LocalTime.of(10, 10, 10);
// 获取时间
time.getHour();
time.getMinute();
time.getNano();
time.getSecond();
// 通过TemporalField获取时间中信息
time.get(ChronoField.HOUR_OF_DAY);
time.get(ChronoField.MINUTE_OF_DAY);
time.get(ChronoField.SECOND_OF_DAY);
字符串转时间:
LocalTime time = LocalTime.parse("20:10:20");
创建对象:
public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute)
public LocalDateTime of(LocalDate date, LocalTime time)
public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute)
通过LocalDate和LocalTime对象生成LocalDateTime对象:
LocalDate date = LocalDate.now();
// 通过 LocalDate 对象的atTime方法生成
LocalDateTime localDateTime = date.atTime(10, 20);// hour minute
LocalTime time = LocalTime.now();
// 通过 LocalTime 的 atDate 方法生成
LocalDateTime localDateTime1 = time.atDate(date);
LocalDateTime转LocalDate和LocalTime:
LocalDateTime now = LocalDateTime.now();
LocalDate date = now.toLocalDate();
LocalTime time = now.toLocalTime();
生成Instant对象:
// 时间戳 毫秒
Instant instant = Instant.ofEpochMilli(100_000);
// 时间戳 秒
Instant instant1 = Instant.ofEpochSecond(100_000);
// 时间戳 秒 + 纳秒
Instant.ofEpochSecond(120, 100_000_000);
从Instant对象中获取时间戳:
Instant.ofEpochSecond(120, 100_000_000);
Instant now = Instant.now();
// 获取秒数
System.out.println(now.getEpochSecond());
// 获取毫秒数
System.out.println(now.toEpochMilli());
// 获取纳秒数
System.out.println(now.getNano());
LocalDateTime dateTime = LocalDateTime.now();
Duration between = Duration.between(dateTime, dateTime);
// Duration 用于获取时间相关 秒和纳秒
System.out.println(between.getSeconds());
LocalDate data = LocalDate.now();
Period between1 = Period.between(data, data);
// Period 主要获取日期相关 年月日等
System.out.println(between1.getYears());
操纵日期:
// 通过 withXxx方法操作日期
LocalDate date = LocalDate.of(2018, 10, 20); // 2018-10-20
LocalDate date1 = date.withYear(2010); // 2010-10-20
LocalDate date2 = date.withMonth(8);// 2010-08-20
LocalDate with = date.with(ChronoField.MONTH_OF_YEAR, 1); // 2018-01-20
// 对日期进行加减操作
LocalDate date3 = date.plusMonths(1); // 2018-11-20
LocalDate plus = date.plus(2, ChronoUnit.MONTHS); // 2018-12-20
// 对日期进行减操作
LocalDate minus = date.minus(10, ChronoUnit.YEARS); // 2008-10-20
按照指定格式转换日期:
// 定义转换格式
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
LocalDate now = LocalDate.now();
// 日期按照指定格式转换
String format = now.format(dateTimeFormatter);
// 默认
LocalDate now = LocalDate.now();
String format = now.format(DateTimeFormatter.BASIC_ISO_DATE); // 20190320
String format1 = now.format(DateTimeFormatter.ISO_DATE); // 2019-03-20
// 反向操作
LocalDate parse = LocalDate.parse("20190320", DateTimeFormatter.BASIC_ISO_DATE);
LocalDate parse1 = LocalDate.parse("2019-03-20", DateTimeFormatter.ISO_DATE);
dayOfWeekInMonth 创建一个新的日期,它的值为同一个月中每一周的第几天
firstDayOfMonth 创建一个新的日期,它的值为当月的第一天
firstDayOfNextMonth 创建一个新的日期,它的值为下月的第一天
firstDayOfNextYear 创建一个新的日期,它的值为明年的第一天
firstDayOfYear 创建一个新的日期,它的值为当年的第一天
firstInMonth 创建一个新的日期,它的值为同一个月中,第一个符合星期几要求的值
lastDayOfMonth 创建一个新的日期,它的值为当月的最后一天
lastDayOfNextMonth 创建一个新的日期,它的值为下月的最后一天
lastDayOfNextYear 创建一个新的日期,它的值为明年的最后一天
lastDayOfYear 创建一个新的日期,它的值为今年的最后一天
lastInMonth 创建一个新的日期,它的值为同一个月中,最后一个符合星期几要求的值
next/previous 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期
nextOrSame/previousOrSame 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期,如果该日期已经符合要求,直接返回该对象
使用示例:
LocalDate lastDayOfMonth = date.with(TemporalAdjusters.lastDayOfMonth());