【Java从入门到放弃 之 Stream API】

发布于:2024-12-06 ⋅ 阅读:(35) ⋅ 点赞:(0)

Stream API

Java8提供了一个全新的API - Stream。引入这个Stream的主要目的,一个是可以支持更好的并发;一个是通过使用Stream可以向方法传递代码(更简洁的形式)

        Collections.sort(list, new Comparator<Stu>() {
            @Override
            public int compare(Stu o1, Stu o2) {
                return o1.score - o2.score;
            }
        });

之前如果我们想给函数传递代码,需要通过匿名类的形式,可以看见这种形式比较繁琐。使用Java8的写法如下

        Collections.sort(list, (o1, o2) -> o1.score - o2.score);

是不是马上就简单了很多呢!

行为参数化传递代码

** 更好地传递代码 **

class Stu {
    private int age;
    private int score;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }
}
    public static List<Stu> filterScoreBigThan60(List<Stu> list) {
        List<Stu> ret = new ArrayList<>();
        for (Stu stu : list) {
            if (stu.getScore() > 60) {
                ret.add(stu);
            }
        }
        return ret;
    }

    public static List<Stu> filterAgeMoreThan15(List<Stu> list) {
        List<Stu> ret = new ArrayList<>();
        for (Stu stu : list) {
            if (stu.getAge() > 15) {
                ret.add(stu);
            }
        }
        return ret;
    }

我们自定义了一个Stu类,下面写了两个静态方法,用来过滤Stu的。观察这两段静态方法的代码,你发现什么了吗?
没错,我们会发现,这两段代码高度地相同。如果我们现在要再写一个过滤超过80分地学生,难道要在把代码复制粘贴一边?这肯定不是很好的实现方式,因为相同代码过多,我们一旦粘贴复制,很有可能会出现忘改某一些地方的情况 如果你现实中做过开发,搞过这种类似需求的代码,你一定明白我说的是啥。复制代码,但是某一些关键要改的地方不小心给漏掉了。而且每一个条件都要新建一个函数,会非常繁琐,函数名也会变得越来越长。

ok,问题我们是知道了,怎么解决了?

  1. 使用策略模式解决
        filterStuByInterface(list, new MyPredicate() {
            @Override
            public boolean test(Stu stu) {
                return stu.getAge() > 60;
            }
        });

    public static List<Stu> filterStuByInterface(List<Stu> list, MyPredicate predicate) {
        List<Stu> ret = new ArrayList<>();
        for (Stu stu : list) {
            if (predicate.test(stu)) {
                ret.add(stu);
            }
        }
        return ret;
    }

我们把一组策略封装到一个策略里面,这里面使用的一个接口。所有的策略都实现这个接口。这样我们的方法就是通用的,每次使用的时候只要传入对应的策略就可以了。

  1. 使用Lambda表达式解决
    public static List<Stu> filterSte(List<Stu> list, Predicate<Stu> predicate) {
        List<Stu> ret = new ArrayList<>();
        for (Stu stu : list) {
            if (predicate.test(stu)) {
                ret.add(stu);
            }
        }
        return ret;
    }

Predicate predicate这个是什么意思呢?Predicate是一个泛型接口,里面有一个test用来返回boolean值。

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}

我们随便通过使用策略模式也可以解决问题,但是通过对比Lambda表达式,我们发现Lambda表达式表达地更加简洁易懂。

Lambda表达式

Lambda 表达式是 Java 8 引入的一项重要特性,它使得代码更加简洁和易读,尤其是在处理集合、并发编程等方面。Lambda 表达式允许你以更函数式的方式编写代码,而不需要显式地创建匿名内部类。

Lambda 表达式的语法

Lambda 表达式的语法非常简洁,通常包括三个部分:参数列表、箭头符号(->)、方法体。

	(parameters) -> expression
	或
	(parameters) -> { statements; }

方法引用

方法引用是一种简化 Lambda 表达式的方式,当 Lambda 表达式只是调用一个已有的方法时,可以使用方法引用来代替 Lambda 表达式。方法引用有以下几种形式:

  • 静态方法引用:ClassName::staticMethod
  • 实例方法引用:instance::instanceMethod
  • 特定类型的方法引用:Type::method
  • 构造方法引用:ClassName::new

Lambda 表达式的实际应用

集合操作

Java 8 引入了流(Stream API),它可以与 Lambda 表达式一起使用,从而简化集合的操作,如过滤、映射、排序等。

	List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
	
	// 过滤出长度大于 5 的名字,并转换为大写
	List<String> filteredNames = names.stream()
	    .filter(name -> name.length() > 5)
	    .map(String::toUpperCase)
	    .collect(Collectors.toList());
	
	System.out.println(filteredNames); // 输出 [CHARLIE]

并发编程

	ExecutorService executor = Executors.newFixedThreadPool(4);
	
	executor.submit(() -> {
	    try {
	        Thread.sleep(1000);
	        System.out.println("Task completed by " + Thread.currentThread().getName());
	    } catch (InterruptedException e) {
	        e.printStackTrace();
	    }
	});
	
	executor.shutdown();

Lambda 表达式的注意事项

  • 访问外部变量:Lambda 表达式可以访问外部的局部变量,但这些变量必须是有效的最终变量(effectively final),即它们在初始化后不能被修改。
  • 多线程安全:虽然 Lambda 表达式本身是线程安全的,但如果它操作共享资源,则需要考虑同步问题。
  • 性能:Lambda 表达式通常比匿名内部类更高效,因为它们避免了额外的类加载和内存分配。

总结

Lambda 表达式是 Java 8 引入的一个强大特性,它使代码更加简洁、易读,并且促进了函数式编程风格的应用。通过 Lambda 表达式,你可以更方便地处理集合、并发编程等问题。希望这些介绍和示例能帮助你更好地理解和使用 Lambda 表达式。如果有任何具体问题或需要进一步的帮助,请随时提问!


网站公告

今日签到

点亮在社区的每一天
去签到