jdk 8 函数式编程 (二)

本文深入探讨Java8中Lambda表达式与Stream API的应用,包括函数接口如Function、Consumer及Predicate的使用,以及如何通过Stream处理集合数据,实现高效的数据过滤、映射与聚合操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1.函数接口

1.1定义

2.2函数接口 

2.流

2.1定义

2.2创建流

2.3中间和终端操作​

3.实际使用

        1.分组计数


如果你发现虽然你的业务代码千差万別,但是它们拥有同样的准备和清理阶段,这时,你完全可以将这部分代码用 Lambda实现。
比如文件流处理异或异常

1.函数接口

1.1定义

  1. 被@FunctionalInterface注释的接口,满足@FunctionalInterface注释的约束。
  2. 没有被@FunctionalInterface注释的接口,但是满足@FunctionalInterface注释的约束

@FunctionalInterface注释的约束

  1. 接口有且只能有个一个抽象方法,只有方法定义,没有方法体
  2. 在接口中覆写Object类中的public方法,不算是函数式接口的方法。
  3. 该注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。 如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错 

@FunctionalInterface简单示例 

	public static void main(String[] args) {

		System.out.println(addstr("a", a -> a + "b"));
		System.out.println(method("a", "b", (a, b) -> a + b));
		System.out.println(method("梁胖子", "你", (a, b) -> a + "❤" + b));
		// JDK8中有双冒号的用法,就是把方法当做参数传过去
		Test1 amethod = My::getInstance;
		System.out.println(method("a", "b", amethod));
	}

	@FunctionalInterface
	public interface Test2 {
		String invoke(String profile);
	}

	@FunctionalInterface
	public interface Test1 {
		String invoke(String profile, String document);
	}

	public static String method(String profile, String document, Test1 a) {
		return a.invoke(profile, document);
	}

	public static String getInstance(String profile, String document) {
		return profile + document;
	}

	public static String addstr(String str, Test2 test2) {
		return test2.invoke(str);
	}

2.2函数接口 

函数接口

 接口名

说明
Function<T,R>   接收一个T类型的参数,返回一个R类型的结果
Consumer<T>接收一个T类型的参数,不返回值
Predicate<T>接收一个T类型的参数,返回一个boolean类型的结果
Supplier<T>不接受参数,返回一个T类型的结果
BiFunction<T, U, R>接收T类型和U类型的两个参数,返回一个R类型的结果
BiConsumer<T , U>接收T类型和U类型的两个参数,不返回值
BiPredicate<T, U>接收T类型和U类型的两个参数,返回一个boolean类型的结果

	public static void main(String[] args) {
		//   Function<T,R>  接收一个T类型的参数,返回一个R类型的结果
		Function<String, String> function = item -> item + item;
		//   Consumer<T>接收一个T类型的参数,不返回值
		Consumer<String> consumer = iterm -> {
			System.out.println(iterm);
		};
		//   Predicate<T>接收一个T类型的参数,返回一个boolean类型的结果
		Predicate<String> predicate = iterm -> "33".equals(iterm);
		//   Supplier<T>不接受参数,返回一个T类型的结果
		Supplier<String> supplier = () -> new String("");

		List<String> list = Arrays.asList("1", "2", "3", "5", "6");

		list.stream().map(function).filter(predicate).forEach(consumer);

		BiFunction<String, String, String> biFunction = (str1, str2) -> str1 + str2;
		BiConsumer<String, String> biConsumer = (str1, str2) -> System.out.println(str1 + str2);
		BiPredicate<String, String> biPredicate = (str1, str2) -> str1.length() > str2.length();
		
		Map<String, String> map = new HashMap<>();
		map.put("java", "boot");
		map.put("spring", "boot");
		map.forEach(biConsumer);
		System.out.println(biFunction.apply("qunimade ", "zhendifan "));
	}

使用default关键字创在interface中直接创建一个default方法,该方法包含了具体的实现代码,说白了就是接口中可以有实现

@FunctionalInterface
public interface BiFunction<T, U, R> {

    /**
     * Applies this function to the given arguments.
     *
     * @param t the first function argument
     * @param u the second function argument
     * @return the function result
     */
    R apply(T t, U u);

    /**
     * Returns a composed function that first applies this function to
     * its input, and then applies the {@code after} function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of output of the {@code after} function, and of the
     *           composed function
     * @param after the function to apply after this function is applied
     * @return a composed function that first applies this function and then
     * applies the {@code after} function
     * @throws NullPointerException if after is null
     */
    default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t, U u) -> after.apply(apply(t, u));
    }
}

2.流

2.1定义

stream只能遍历一次

for外部迭代,stream内部迭代

操作分为两种中间操作、终端操作,中间操作会返回一个流,并链接在一起形成一条流水线,但并不会生成任何结果,只有遇到终端操作才处理流水线并返回结果

函数式接口就是只定义一个抽象方法的接口,比如Comparator 和 Runnable 。

lamada基本语法

(parameters) -> expression或者(parameters) -> { statements; } 注意花括号

如果你发现虽然你的业务代码千差万別,但是它们拥有同样的准备和清理阶段,这时,你完全可以将这部分代码用 Lambda实现。
比如文件流处理异常

2.2创建流

  1.值创建流   

Stream<String> stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action");

2.数组创建流

  int[] numbers = {2, 3, 5, 7, 11, 13};
  int sum = Arrays.stream(numbers).sum();

3.由文件创建流

  Files.lines(Paths.get("data.txt"), Charset.defaultCharset())){
        uniqueWords = lines.flatMap(line -> Arrays.stream(line.split(" ")))
        .distinct()
        .count();

4.由函数生成流:创建无限流

   Stream.iterate(0, n -> n + 2)
    .limit(10)
    .forEach(System.out::println);

      数列中开始的两个数字是0和1,后续的每个数字都是前两个数字和
         Stream.iterate(new int[]{0, 1}, a -> new int[]{a[0]+a[1],a[0]+a[1]+a[1]})
         .limit(20)
         .forEach(t -> System.out.println("(" + t[0] + "," + t[1] +")"));

5.生成

  generate 方法可以按需生成一个无限流,但generate不是依次对每个新生成的值应用函数的,他接收Supplier的lamada新值
  Stream.generate(Math::random)
         .limit(5)
         .forEach(System.out::println);
          IntStream.generate(() -> 1).limit(30).forEach(System.out::println);
          
          Stream.generate(new Supplier<String>(){
             public String get(){
             return "aaa";
             }
             }).limit(30).forEach(System.out::println);;

2.3中间和终端操作

所有元素和
int sum = numbers.stream().reduce(0, (a, b) -> a + b);
int sum = numbers.stream().reduce(0, Integer::sum);

 获取每个元素长度累加和
Integer reduce2 = list.stream().map(a -> a.toString().length()).reduce(0,Integer::sum);
 
 两个集合每个元素相乘 返回一个总集合
 List<Integer> numbers1 = Arrays.asList(1, 2, 3);
 List<Integer> numbers2 = Arrays.asList(3, 4);
 List<String> collect2 = numbers1.stream().flatMap(a ->  numbers2.stream().map(b -> a+"*"+b)).collect(Collectors.toList());
 

 int calories = list.stream().map(Integer::byteValue).sum();
 int calories = list.stream().mapToInt(Integer::byteValue).sum();
  第一个是错误的没有sum方法,必须转化为IntStream才有sum方法,这是因为map返回的是T类型
 intStream.boxed()可以将IntStream转化为Stream
  int 和 Integer效率差异
  IntStream性能优于Stream 避免了自动拆箱等操作
  
  输出1到100的偶数  
 rangeClosed和range生成1到100的所有数字 rang不包含结尾,rangeClosed包含结尾
 IntStream.rangeClosed(1, 100).filter(n -> n % 2 == 0).forEach(System.out::print);


计数、汇总、最大值
menu.stream().collect(Collectors.counting());或者 menu.stream().count();
menu.stream().collect(Collectors.summingInt());
menu.stream().collect(Collectors.maxBy((a,b) -> a-b));

3.实际使用

        1.分组计数

Map<Long, Long> collect = bargainInviteRecordDos.stream().collect(Collectors.groupingBy(BargainInviteRecordDo::getSpuId, Collectors.mapping(BargainInviteRecordDo::getSpuId, Collectors.counting())));

                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值