只包含一个抽象方法的接口,称为函数式接口
。
可以通过Lambda表达式来创建该接口的对象。(若 Lambda 表达式 抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽象方法上进行声明)。
我们可以在一个接口上使用 @FunctionalInterface
注解,这样做可以检查它是否是一个函数式接口。同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。
在java.util.function包下定义了Java 8 的丰富的函数式接口
Java从诞生日起就是一直倡导“一切皆对象”,在Java里面面向对象(OOP) 编程是一切。但是随着python、scala等语言的兴起和新技术的挑战,Java不 得不做出调整以便支持更加广泛的技术要求,也即java不但可以支持OOP还 可以支持OOF(面向函数编程)
在函数式编程语言当中,函数被当做一等公民对待。在将函数作为一等公民的编程语言中,Lambda表达式的类型是函数。但是在Java8中,有所不同。在Java8中,Lambda表达式是对象,而不是函数,它们必须依附于一类特别的 对象类型——函数式接口。
简单的说,在Java8中,Lambda表达式就是一个函数式接口的实例。这就是 Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口 的实例,那么该对象就可以用Lambda表达式来表示。
以前用匿名实现类表示的现在都可以用Lambda表达式来写。
Runnable就是典型的函数式接口
。接口上放带有@FunctionalInterface注解
,接口中又只有一个抽象方法。
@FunctionalInterface
public interface InterA {
void show() ;
}
@FunctionalInterface
public interface InterB {
int show() ;
}
Lambda是一个匿名函数
,我们可以把 Lambda表达式理解为是一段可以传递的代码
(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
- Lambda表达式是在Java8中引入的一种新的语法元素和操作符。这个操作符为
->
,该操作符被称为Lambda操作符或箭头操作符。它将Lambda分为两部分:
- 左侧:是Lambda表达式需要的
参数列表
- 右侧:指定了Lambda体,是抽象方法的实现逻辑,也就是Lambda表达式要执行的功能
无参,无返回值
public class Demo1 {
public static void main(String[] args) {
InterA a = () -> System.out.println("无参无返回值的Lambda表达式") ;
a.show();
}
}
@FunctionalInterface
interface InterA {
void show() ;
}
一个参数,没有返回值
public class Demo2 {
public static void main(String[] args) {
// Lambda表达式
// InterB b = (int num) -> System.out.println(num) ;
// 参数的数据类型可以省略,编译器可以推断得出,称为”类型推断“参数的类型和包括,当Lambda表达式只需要一个参数时,参数的小括号可以省略,
// InterB b = (num) -> System.out.print(num) ;
InterB b = num -> System.out.println(num) ;
b.show(10);
}
}
@FunctionalInterface
interface InterB {
public abstract void show(int num) ;
}
Lambda 需要两个或以上的参数,多条执行语句,并且有返回值
public class Demo3 {
public static void main(String[] args) {
InterC c = ((s1, s2) -> {
System.out.println("两个及以上参数,有返回值");
return s1 + s2 ;
}) ;
System.out.println(c.show("Hello", " World"));
}
}
@FunctionalInterface
interface InterC {
String show(String s1 , String s2) ;
}
当Lambda有返回值,且只有一条语句时
public class Demo4 {
public static void main(String[] args) {
InterD d = (a , b) -> Integer.max(a , b) ;
System.out.println(d.max(5, 7));
}
}
@FunctionalInterface
interface InterD {
int max(int a , int b) ;
}
- 类型推断
- Lambda 表达式中的参数类型都是由编译器推断得出的。Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac
根据程序的上下文,在后台推断出了参数的类型。Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的“类型推断”。
::
” 将类(或对象) 与 方法名分隔开来。对象::实例方法名
类::静态方法名
类::实例方法名
如:
InterB b = num -> System.out.println(num) ;
——> InterB b = System.out::println ;
InterD d = (a , b) -> Integer.max(a , b) ;
——> InterD d = Integer::max;
InterD d = ((a, b) -> a.equals(b));
——> InterD d = String::equals;
类名::方法名
格式:类名::new
与函数式接口相结合,自动与函数式接口中方法兼容。
可以把构造器引用赋值给定义的方法,要求构造器参数列表要与接口中抽象方法的参数列表一致。且方法的返回值即为构造器对应类的对象。
示例:
public class Demo5 {
public static void main(String[] args) {
/*Inter1 inter2 = new Inter1() {
@Override
public Date getTime() {
return new Date();
}
} ;*/
// Inter1 inter1 = () -> new Date();
Inter1 time = Date::new ;
System.out.println(time.getTime());
}
}
@FunctionalInterface
interface Inter1 {
Date getTime() ;
}
type[]::new
示例:
public class Demo6 {
public static void main(String[] args) {
/*Inter2 inter2 = new Inter2() {
@Override
public int[] show(int length) {
return new int[length];
}
} ;*/
// Inter2 inter2 = length -> new int[length] ;
Inter2 inter2 = int[]::new;
}
}
@FunctionalInterface
interface Inter2 {
int[] show(int length) ;
}
Stream 是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。 集合讲的是数据,Stream讲的是计算
- Stream本身不会存储数据
- Stream不会改变源对象,每次对源对象进行操作都会返回一个新的Stream流
- Stream操作是延迟执行的,这意味着Stream会等到需要结果时才执行
- 1、创建Stream
- 一个数据源,如通过集合、数组获取一个Stream流
- 2、中间操作
- 一个中间操作链,使用Stream类中的方法对数据进行处理
- 3、中止操作
- 一旦执行中止操作,Stream流就会执行中间操作链,并产生结果。
default Stream stream()
: 返回一个顺序流default Stream parallelStream()
: 返回一个并行流
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list , "张三" , "李四" , "王五" , "赵六") ;
// 使用集合创建Stream流对象
Stream<String> stream = list.stream();
Arrays 的静态方法
stream()
可以获取数组流
- static Stream stream(T[] array): 返回一个流
public static IntStream stream(int[] array)
public static LongStream stream(long[] array)
public static DoubleStream stream(double[] array
public class Demo2 {
public static void main(String[] args) {
int[] arr = {1 , 5 , 3 , 2 , 4} ;
long[] arr1 = {1 , 5 , 3 , 2 , 4} ;
double[] arr2 = {1 , 5 , 3 , 2 , 4} ;
IntStream stream = Arrays.stream(arr);
LongStream stream1 = Arrays.stream(arr1);
DoubleStream stream2 = Arrays.stream(arr2);
}
}
调用Stream类静态方法 of()
, 通过显示值创建一个流。它可以接收任意数量的同种数据类型的参数。
public static Stream of(T... values)
: 返回一个流
示例:
public class Demo3 {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<String> stream1 = Stream.of("张三", "李四", "王五", "赵六");
}
}
Stream.iterate()
和 Stream.generate()
, 创建无限流。
- 迭代
public static
Stream iterate(final T seed, final UnaryOperator f) - 生成
public static
Stream generate(Supplier s)
示例:
public class Demo4 {
public static void main(String[] args) {
Stream<Integer> stream = Stream.iterate(0, x -> x + 2); // 0 2 4 6 8 ... 18
stream.limit(10).forEach(System.out::println);
// 生成
Stream<Double> stream1 = Stream.generate(Math::random); // 10random生成的随机数个随机数
stream1.limit(10).forEach(System.out::println);
}
}
惰性求值
”。
filter(Predicate p)
:接收 Lambda , 从流中排除某些元素distinct()
:筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素limit(long maxSize)
:截断流,使其元素不超过给定数量skip(long n)
:跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一 个空流。与 limit(n) 互补
public class FilterDemo {
public static void main(String[] args) {
int[] arr = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10} ;
IntStream stream = Arrays.stream(arr);
/*stream.filter(new IntPredicate() {
@Override
public boolean test(int value) {
return value > 5;
}
}) ;*/
// 调用filter()方法,筛选出大于5的元素
IntStream stream1 = stream.filter(value -> value > 5);
stream1.forEach(System.out::println);
}
}
public class DistinctDemo {
public static void main(String[] args) {
int[] arr = {1 , 2 , 3 , 4 , 5 , 1 , 2 , 3 , 4 , 5} ;
IntStream stream = Arrays.stream(arr);
// 使用distinct()方法去除Stream流中的重复元素
stream.distinct().forEach(System.out::println);
}
}
public class LimitDemo {
public static void main(String[] args) {
int[] arr = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10} ;
IntStream stream = Arrays.stream(arr);
// 调用limit()方法
stream.limit(3).forEach(System.out::println);
}
}
public class SkipDemo {
public static void main(String[] args) {
int[] arr = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10} ;
IntStream stream = Arrays.stream(arr);
stream.skip(5).forEach(System.out::println);
}
}
map(Function f)
:接收一个函数作为参数,该函数会被应用到每个元 素上,并将其映射成一个新的元素。mapToDouble(ToDoubleFunction f)
: 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的DoubleStream。mapToInt(ToIntFunction f)
: 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 IntStream。mapToLong(ToLongFunction f)
:接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 LongStream。flatMap(Function f)
: 接收一个函数作为参数,将流中的每个值都换成另 一个流,然后把所有流连接成一个流
public class MapDemo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list , "张三" , "李四" , "王五" , "赵六") ;
/*list.stream().map(new Function() {
@Override
public Student apply(String s) {
return new Student(s);
}
}) ;*/
// 将String类型转为Student类型
// 简化的写法,构造器引用并遍历
list.stream().map(Student::new).forEach(System.out::println); ;
}
}
public class MapToIntDemo {
public static void main(String[] args) {
String[] arr = {"12" , "5" , "8" , "3" , "88" , "99"} ;
Stream<String> stream = Arrays.stream(arr);
// 调用mapToInt()方法,将String类型转为int类型
/*stream.mapToInt(new ToIntFunction() {
@Override
public int applyAsInt(String value) {
return Integer.parseInt(value);
}
}).forEach(System.out::println); */
// 方法引用方式
stream.mapToInt(Integer::parseInt)
.forEach(System.out::println);
}
}
sorted()
产生一个新流,其中按自然顺序排序sorted(Comparator com)
产生一个新流,其中按比较器顺序排序
public class SortedDemo1 {
public static void main(String[] args) {
Stream<String> stream = Stream.of("7", "5", "8", "3", "1", "9");
// 调用sorted()方法进行排序,排序规则为String默认规则
stream.sorted().forEach(System.out::println);
}
}
public class SortedDemo2 {
public static void main(String[] args) {
String[] arr = {"7", "5", "8", "3", "1", "9"} ;
Arrays.stream(arr).sorted(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return Integer.parseInt(o2) - Integer.parseInt(o1) ;
}
}).forEach(System.out::println);
// lambda表达式写法
Arrays.stream(arr)
.sorted((o1 , o2) -> Integer.parseInt(o2) - Integer.parseInt(o1))
.forEach(System.out::println);
}
}
allMatch(Predicate p)
: 检查是否匹配所有元素anyMatch(Predicate p)
: 检查是否至少匹配一个元素noneMatch(Predicate p)
: 检查是否没有匹配所有元素findFirst()
: 返回第一个元素findAny()
: 返回当前流中的任意元素count()
:返回流中元素总数max(Comparator c)
:返回流中最大值min(Comparator c)
:返回流中最小值forEach(Consumer c)
:内部迭代(使用 Collection 接口需要用户去做迭代, 称为外部迭代。相反,Stream API 使用内部迭 代——它帮你把迭代做了)
public class AllMatchDemo {
public static void main(String[] args) {
// 创建Stream流对象
Stream<Integer> stream = Stream.of(2, 2, 1, 2, 2);
Stream<Integer> stream1 = Stream.of(2, 2, 2, 2, 2);
// 如果流中的所有元素都为2,则返回true
boolean allMatch = stream.allMatch(new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
return integer == 2;
}
});
System.out.println(allMatch); // false
boolean allMatch1 = stream1.allMatch(num -> num == 2);
System.out.println(allMatch1); // true
}
}
public class AnyMatchDemo {
public static void main(String[] args) {
// 创建Stream流
Stream<Integer> stream = Stream.of(5, 1, 4, 3, 7);
/*boolean anyMatch = stream.anyMatch(new Predicate() {
@Override
public boolean test(Integer integer) {
return integer == 3;
}
});*/
boolean anyMatch = stream.anyMatch(num -> num == 3);
System.out.println(anyMatch); // true
}
}
public class NoneMatchDemo {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5);
// 检查流中是否所有的元素都不匹配
boolean noneMatch = stream.noneMatch(num -> num > 6);
System.out.println(noneMatch); // true
boolean noneMatch1 = stream1.noneMatch(num -> num < 2);
System.out.println(noneMatch1); // false
}
}
public class FindFirstDemo {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(7, 2, 3, 4, 5);
Stream<Integer> stream1 = Stream.of(7, 2, 3, 4, 5);
// 返回第一个元素
Optional<Integer> first = stream.findFirst();
System.out.println(first);
// 返回任意一个元素
Optional<Integer> any = stream1.findAny();
System.out.println(any);
}
}
count()
max(Comparator c)
min(Comparator c)
public class Demo5 {
public static void main(String[] args) {
Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> stream2 = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> stream3 = Stream.of(1, 2, 3, 4, 5);
// 获取流中元素个数
long count = stream1.count();
System.out.println(count);
// 获取流中最大值
Optional<Integer> max = stream2.max(Comparator.comparingInt(o -> o));
System.out.println(max);
// 获取流中最小值
Optional<Integer> min = stream3.min(Comparator.comparingInt(o -> o));
System.out.println(min);
}
}
public class ForEachDemo {
public static void main(String[] args) {
Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> stream2 = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> stream3 = Stream.of(1, 2, 3, 4, 5);
stream1.forEach(integer -> System.out.println(integer + 1)); // 2 3 4 5 6
stream2.forEach(System.out::println);
stream3.forEach(integer -> System.out.println(integer = 0));
}
}
reduce(T iden, BinaryOperator b)
: 可以将流中元素反复结合起来,得到一 个值。返回 Treduce(BinaryOperator b)
: 可以将流中元素反复结合起来,得到一 个值。返回 Optional
public class ReduceDemo {
public static void main(String[] args) {
Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> stream2 = Stream.of(1, 2, 3, 4, 5);
// 求流中元素的和
Integer reduce = stream1.reduce(10, (integer, integer2) -> integer + integer2);
System.out.println(reduce); // 25 = 10 + (1 + 2 + 3 + 4 + 5)
Optional<Integer> sum = stream2.reduce(Integer::sum);
System.out.println(sum); // 15
}
}
collect(Collector c)
: 将流转换为其他形式。接收一个 Collector 接口的实现,用于给Stream中元素做汇总的方法
Collector 接口中方法的实现决定了如何对流执行收集的操作(如收集到 List、Set、 Map)。
toList
: 把流中元素收集到List
toSet
: 把流中元素收集到Set
toCollection
: 把流中元素收集到创建的集合
public class CollectDemo1 {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> stream2 = Stream.of(1, 2, 3, 4, 5);
// 将流中数据收集到List集合中
List<Integer> list = stream.collect(Collectors.toList());
System.out.println(list);
// 将流中数据收集到set集合
Set<Integer> set = stream1.collect(Collectors.toSet());
System.out.println(set);
// 将流中数据收集到Collection集合
ArrayList<Integer> arrayList = stream2.collect(Collectors.toCollection(ArrayList::new));
System.out.println(arrayList);
}
}
java.util.Optional
) 是一个容器类
,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用 null 表示一个值不 存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。
- 创建Optional类对象的方法:
Optional.of(T t)
: 创建一个 Optional 实例,t必须非空;Optional.empty()
: 创建一个空的 Optional 实例Optional.ofNullable(T t)
:t可以为null- 判断Optional容器中是否包含对象:
boolean isPresent()
: 判断是否包含对象void ifPresent(Consumer super T> consumer)
:如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它。- 获取Optional容器的对象:
T get()
: 如果调用对象包含值,返回该值,否则抛异常T orElse(T other)
:如果有值则将其返回,否则返回指定的other对象。T orElseGet(Supplier extends T> other)
:如果有值则将其返回,否则返回由Supplier接口实现提供的对象。T orElseThrow(Supplier extends X> exceptionSupplier)
:如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。
public class OptionalDemo {
public static void main(String[] args) {
// 创建Optional类的实例
Optional<Integer> o = Optional.of(1);
// 判断Optional实例中是否包含对象(类似于非空校验)
boolean present = o.isPresent();
System.out.println(present);
// 如果存在就执行Consumer接口中实现的代码
o.ifPresent(new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
System.out.println(integer);
}
});
// lambda表达式 , 方法引用
// o.ifPresent(System.out::println);
// 获取对象值
System.out.println(o.get());
// 有值则返回值,无值返回0
Integer integer = o.orElse(0);
System.out.println(integer);
// 有值则返回值,无值则执行Supplier接口中的代码
Integer integer1 = o.orElseGet(new Supplier<Integer>() {
@Override
public Integer get() {
return 0;
}
});
System.out.println(integer1);
}
}