5.Lambda 表达式:Lambda 表达式是函数式编程语言中的一种匿名函数。它可以用于定义简短的函数体,方便地将函数作为参数传递给其他函数或者直接返回一个函数。
在 Scala 中,函数式编程和面向对象编程可以自由地混用,使得代码更加灵活和简洁。
传统命令式编程则更加强调使用语句式的编程风格,强调计算的过程和状态的改变。
AVA 函数式编程的特性主要是在 Java 8 引入的新特性,主要包括Lambda 表达式、函数式接口以及Stream API。Lambda 表达式是函数式编程的核心特性之一。它是一种匿名函数,允许将函数作为参数传递给其他函数或直接返回一个函数。
Lambda 表达式:可以使代码更加简洁、灵活,减少冗余代码,并且在集合操作中有着广泛的应用。
// 传统的匿名内部类写法 Runnable runnable1 = new Runnable() { @Override public void run() { System.out.println("Hello, World!"); } }; // 使用 Lambda 表达式 Runnable runnable2 = () -> System.out.println("Hello, World!");函数式接口: 函数式接口是只包含一个抽象方法的接口,通过 @FunctionalInterface 注解标识。函数式接口用于支持 Lambda 表达式,让开发者可以在不声明新接口的情况下,直接使用已有的接口。
@FunctionalInterface public interface C300_Function { int apply(int x, int y); }Stream API: 提供了一套丰富的函数式操作,用于对集合数据进行过滤、映射、排序、归约等处理。Stream API 避免了显式使用迭代器或循环,使得代码更加简洁和易读。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); int sum = numbers.stream().filter(n -> n % 2 == 0).mapToInt(Integer::intValue).sum();这儿主要先研究下@FunctionallInterface注解
在Spring中很多注解(特别是)是通过代理实现的,特别是与 AOP(Aspect-Oriented Programming,面向切面编程)相关的注解。 Spring 使用代理来实现 AOP 的横切关注点,比如事务管理、日志记录等。,但上述这个接口只是用来起标识作用,当接口被这个注解标识的话那么就只能有一个抽象方法接口,目的是为了保证接口的设计人员在接口中添加多个抽象方法时能够在编译时得到错误提示。
例如一个接口标记了 @FunctionalInterface 注解若它包含多个抽象方法,编译器会报错。一般函数式接口只能有一个抽象方法,并且排除接口默认(default)方法及声明中覆盖Object的公开方法,同时,@FunctionalInterface不能标注在注解、类、枚举上。如果违背以上的原则那么这个接口就不能视为函数式接口,当标注这个注解后编译会报错, 不过任何一个接口满足上述函数式接口的要求后,无论接口上是否添加@FunctionallInterface注解都能被编译器视为函数式接口。无论是哪一种注解其实都是数据流转对象。
@FunctionalInterface public interface C301_FunctionalInterface { /** * 重写的方法不算,因为会默认调用其继承父类的这个方法 */ @Override String toString(); /** * default方法由于会在定义时实现,所以不作为函数式接口唯一的方法的要求 * * @return String */ default String toUpperCase() { return "toUpperCase"; } void test(); public static void main(String[] args) { /**调用之前需要先实现其定义的方法 test(),这个地方也就体现出为啥只能定义一个抽象方法,否则该如何表示实现哪个默认方法呢?*/ C301_FunctionalInterface functionalInterface = () -> { System.out.println("test"); }; /**调用了其定位的方法*/ functionalInterface.test(); System.out.println(functionalInterface.toUpperCase()); System.out.println(functionalInterface.toString()); } }Note that instances of functional interfaces can be created with lambda expressions, method references, or constructor references.
/** * Represents a supplier of results. * * <p>There is no requirement that a new or distinct result be returned each * time the supplier is invoked. * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #get()}. * * @param <T> the type of results supplied by this supplier * * @since 1.8 */ @FunctionalInterface public interface Supplier<T> { /** * Gets a result. * * @return a result */ T get(); }示例使用 Supplier 接口:
import java.util.function.Supplier; public class SupplierExample { public static void main(String[] args) { Supplier<String> messageSupplier = () -> "Hello, World!"; String message = messageSupplier.get(); System.out.println(message); // 输出:Hello, World! } }在上面的示例中,我们使用了 Supplier<String> 函数式接口创建了一个供给型对象 messageSupplier,它返回一个固定的字符串 "Hello, World!"。然后通过调用 messageSupplier.get() 方法获取供给型对象的结果。
@FunctionalInterface public interface Consumer<T> { /** * Performs this operation on the given argument. * * @param t the input argument */ void accept(T t); /** * Returns a composed {@code Consumer} that performs, in sequence, this * operation followed by the {@code after} operation. If performing either * operation throws an exception, it is relayed to the caller of the * composed operation. If performing this operation throws an exception, * the {@code after} operation will not be performed. * * @param after the operation to perform after this operation * @return a composed {@code Consumer} that performs in sequence this * operation followed by the {@code after} operation * @throws NullPointerException if {@code after} is null */ default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }案例
public class C303_Consumer { public static void main(String[] args) { Consumer consumer = System.out::println; Consumer<String> consumer2 = C303_Consumer::println; // 轮流消费 consumer2.andThen(consumer).andThen(consumer2).andThen(consumer2).accept("hello world2"); consumer.accept("hello world1"); } public static void println(String message){ System.out.println("println:"+message); } }打印结果:
println:hello world2 hello world2 println:hello world2 println:hello world2 hello world1理解Function<T,R>
public class C304_Function { public static void main(String[] args) { /**示例一:将入参为String转为Integer类型返回*/ Function <String,Integer> function1 = new Function<String, Integer>() { @Override public Integer apply(String s) { System.out.println("function1"); return Integer.parseInt(s); } }; /**通过Function里面的apply函数调用*/ // System.out.println(function1.apply("123")); /**示例二:将入参为Integer转为String类型返回*/ Function<Integer,String> function2 = new Function<Integer, String>() { @Override public String apply(Integer integer) { System.out.println("function2"); return String.valueOf(integer); } }; /**示例三:将入参为String转为String类型返回*/ Function<String,String> function3 = new Function<String, String>() { @Override public String apply(String string) { System.out.println("function3"); return String.valueOf(string); } }; // 执行循序:fun2 -> fun3 -> fun1 Integer apply = function1.compose(function3).compose(function2).apply(123456); } }打印结果:
function2 function3 function1Function 接口在 Java 中广泛用于集合框架的操作,例如 List 的 map() 方法接受一个 Function 对象作为参数,用于对集合中的每个元素进行映射转换。另外,在 Stream API 中也经常使用 Function 接口进行数据转换和处理。
import java.util.Arrays; import java.util.List; import java.util.function.Function; public class FunctionExample { public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); // 使用 Function 接口处理集合元素 Function<String, Integer> nameLengthMapper = name -> name.length(); names.stream() .map(nameLengthMapper) .forEach(System.out::println); } }理解Predicate<T>
public class C305_Predicate { /** * Predicate<T>:这一接口定了一个默认方法:boolean test(T t),这一方法用检查给定的参数是否符合查询检查。 * Predicate<T>接口中有两中重要的方法:and(),or(),negate()。 * Predicate<T>接口中的方法如下: * and(Predicate<? super T> other):对当前 Predicate 和另一个 Predicate 进行逻辑与操作。 * or(Predicate<? super T> other):对当前 Predicate 和另一个 Predicate 进行逻辑或操作。 * negate():返回当前 Predicate 的逻辑非。 * 下面是使用 Predicate 进行条件组合的示例: */ public static void main(String[] args) { //能够被2整除 Predicate<Integer> dividedTwo = new Predicate<Integer>() { @Override public boolean test(Integer o) { return o % 2 == 0; } }; //能够被3整除 Predicate<Integer> dividedThree = o -> o % 3 == 0; //能够被5整除 Predicate<Integer> dividedFive = o -> o % 5 == 0; //Predicate 支持多种逻辑操作,可以通过 and、or、negate 等方法将多个 Predicate 进行组合,形成更复杂的条件。 // and使用:true System.out.println(dividedTwo.and(dividedThree).and(dividedFive).test(30)); // or使用:false System.out.println(dividedTwo.and(dividedThree).or(dividedFive).test(3)); // negate使用:true System.out.println((dividedTwo.and(dividedThree).or(dividedFive)).negate().test(3)); } }FunctionPredicate应用
/** * 过滤函数,将集合内满足一定条件的元素返回 * * @param sourece 源数据集合 * @param predicate 处理函数Function * @param <T> * @return 满足断言的所有数据源集合 * TODO: 我这儿用一个List接收,我理解这不够抽象 */ public static <T> Collection<T> filter_1(Collection<? extends T> sourece, Function<T, Boolean> predicate) { Collection<T> temp = new ArrayList<T>(); for (T t : sourece) { if (predicate.apply(t)) { temp.add(t); } } return Collections.unmodifiableCollection(temp); }断言作过滤函数
/** * 堆代码 duidaima.com * @param sourece 输入数据集合 * @param predicate 断言 * @param <E> 泛型 * @return */ public static <E> Collection<E> filter_2(Collection<? extends E> sourece, Predicate<E> predicate) { Collection<E> temp = new ArrayList<E>(); for (E t : sourece) { if (predicate.test(t)) { temp.add(t); } } return Collections.unmodifiableCollection(temp); } // 调用 public static void testFilter_2() { Collection<Integer> collection = filter_2(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (Integer i) -> { return i % 2 == 0; }); System.out.println(collection); }隐藏类型-Action
public class C3_06_Action { public static void main(String[] args) { // 匿名内置类实现 Runnable runnable = new Runnable() { @Override public void run() { System.out.println("定时任务执行"); } }; Thread thread = new Thread(runnable); // invokeDynamic指令实现的(反汇编) // MethodHandle Runnable r = () -> System.out.println("定时任务执行"); Thread t = new Thread(r); } }理解Stream
/** * Returns an equivalent stream that is sequential. May return * itself, either because the stream was already sequential, or because * the underlying stream state was modified to be sequential. * * <p>This is an <a href="package-summary.html#StreamOps">intermediate * operation</a>. * * @return a sequential stream */ S sequential(); /** * Returns an equivalent stream that is parallel. May return * itself, either because the stream was already parallel, or because * the underlying stream state was modified to be parallel. * * <p>This is an <a href="package-summary.html#StreamOps">intermediate * operation</a>. * * @return a parallel stream */ S parallel();示例使用 Stream API:
import java.util.Arrays; import java.util.List; public class StreamExample { public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eva"); // 使用 Stream API 对集合进行操作 long count = names.stream() .filter(name -> name.length() <= 4) .map(String::toUpperCase) .sorted() .count(); System.out.println(count); // 输出:4 } }在上面的示例中,我们使用 Stream API 对集合 names 进行一系列的操作:首先用 filter 过滤掉长度大于 4 的字符串,然后用 map 将字符串转换为大写,接着用 sorted 进行排序,最后用 count 终端操作统计符合条件的元素个数。
public class C03_08_Stream { public static void main(String[] args) { sorted(Integer::compareTo, Arrays.asList(5, 1, 5, 4, 8, 9, 6, 5, 4, 8, 5, 4, 2, 3, 4)).stream().distinct().forEach(System.out::println); } /** * sorted<Comparator<? super T> comparator>的使用 * @param comparator 比较器 * @param collection 待排序的集合 * @param <T> * @return 排序后的集合 */ private static <T> Collection<T> sorted(Comparator<T> comparator, Collection<T> collection) { return collection.stream().sorted(comparator).collect(Collectors.toList()); } }map的应用
/** * Stream 的 map<Function>操作 * * @param integers */ private static void count(Integer... integers) { Stream.of(integers) .map(Long::valueOf) .reduce(Long::sum) .ifPresent(System.out::println); }并行parallel
/** * 并行parallel案例 * @param integers */ private static void parallelSort(Integer... integers){ Stream.of(integers).sorted(Integer::compareTo).parallel().forEach(C03_08_Stream::println); } public static void println(Object obj){ System.out.printf("[%s]:%s \n",Thread.currentThread().getName(),obj); }打印结果
// 堆代码 duiaima.com [main]:7 [ForkJoinPool.commonPool-worker-2]:1 [ForkJoinPool.commonPool-worker-2]:4 [ForkJoinPool.commonPool-worker-9]:8 [ForkJoinPool.commonPool-worker-6]:3 [ForkJoinPool.commonPool-worker-13]:6 [ForkJoinPool.commonPool-worker-15]:5 [ForkJoinPool.commonPool-worker-4]:9 [ForkJoinPool.commonPool-worker-11]:2 [main]:1这个默认创建系统设置的线程数(NUMBER_OF_PROCESSORS)
/**collect的使用案例 * @param integers * @return */ public static List<Integer> collect(Integer... integers){ List<Integer> collect = Stream.of(integers).collect(Collectors.toList()); List<Integer> collect2 = Stream.of(integers).collect(LinkedList::new,LinkedList::add,LinkedList::addAll); return collect; }理解flatMap
static class Klass { private String name; public Klass(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Klass{" + "name='" + name + '\'' + '}'; } } static class KlassGroup { private List<Klass> group = new ArrayList<>(); public KlassGroup(Klass... klass) { group.addAll(Arrays.asList(klass)); } public List<Klass> getGroup() { return group; } } // 现在要做的一件事是如果有多个List<Klass>想合并成一个List<Klass> /** * 关于flatMap的使用 * @param klassLoist * @return */ public static List<Klass> mergeKlass(List<List<Klass>> klassLoist){ return klassLoist.stream().flatMap(Collection::stream).collect(Collectors.toList()); }函数式编程的局限性