Lambda And Stream

Lambda And Stream

一、函数式编程

面向对象编程是对数据进行抽象,函数式编程是对行为进行抽象,能编写出易读的代码,便于维护、可靠性高

1.函数式接口

标椎@FunctionalInterface注解的接口,接口中只能有一个抽象方法(覆盖

java.lang.Object的公共方法的抽象方法不计入),但可以有多个默认实现

//标记注解 如果接口不满足条件会在编译时报错
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

eg.

@FunctionalInterface
public interface Runnable {
    
    public abstract void run();
}
//自定义接口
@FunctionalInterface
interface A {

    void f1();

    //默认实现
    default void f2() {
        System.err.println("111");
    }
}
//匿名内部类
Runnable r1 = new Runnable() {
    @Override
    public void run() {
        System.out.println("r1 run...");
    }
};

//lambda表达式
//Runnable r2 = () -> System.out.println("r2 run...");
//可以进行强制类型转换
Object r2 = (Runnable) () -> System.out.println("r2 run...");


Thread t1 = new Thread(r1);
//Thread t2 = new Thread(r2);
Thread t2 = new Thread((Runnable) r2);
2.Lambda表达式写法
@FunctionalInterface
interface B {

    int doubleNum(int number);
}
B b1 = (number) -> number * 2;

//一个参数可省略小括号 方法体只有一行 可以省略return
B b2 = number -> number * 2;

//参数可以声明类型
B b3 = (int number) -> number * 2;

//多行方法体需要用大括号包裹
B b4 = (int number) -> {
    System.out.println("doubleNum()...");
    return number * 2;
};
3.常用函数接口
Function
//一个参数一个返回值 T ---> 参数类型  R ---> 返回值
@FunctionalInterface
public interface Function<T, R> {

    R apply(T t);
		
    ...
}
public static void main(String[] args) {

    Scanner scanner = new Scanner(System.in);

    Function<String, String> function = (str) -> {
        System.out.println("请输入一个字符串:");
        return scanner.nextLine();
    };

    System.out.println("你输入的是:" + function.apply("1"));
}

/*
请输入一个字符串:
dssad
你输入的是:dssad
*/
Predicate
//一个参数 返回值为布尔类型 T ---> 参数类型 返回值为boolean
@FunctionalInterface
public interface Predicate<T> {

    boolean test(T t);
    
    ...
}
public static void main(String[] args) {

    Predicate<String> predicate = (str) -> {
        return str.isEmpty();
    };

    System.out.println(predicate.test(""));
}

//true
Consumer
//一个参数 没有返回值 T ---> 参数类型 没有返回值
@FunctionalInterface
public interface Consumer<T> {

    void accept(T t);
    
    ...
}
public static void main(String[] args) {

    Consumer<String> consumer = (str) -> {
        System.out.println("str = " + str);
    };

    consumer.accept("asdasxax");
}

//str = asdasxax
Supplier
//没有参数 一个返回值 T ---> 返回值类型 没有参数
@FunctionalInterface
public interface Supplier<T> {

    T get();
}
public static void main(String[] args) {

    Supplier<String> supplier = () -> {return "asd";};

    System.out.println(supplier.get());
}

//asd
UnaryOperator
//一个参数 一个返回值 参数类型和返回值类型相同
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {

    static <T> UnaryOperator<T> identity() {
        return t -> t;
    }
}
public static void main(String[] args) {
    //参数和返回值类型都是Integer
    UnaryOperator<Integer> unaryOperator = num -> num * 2;
    System.out.println(unaryOperator.apply(2));
}

//4
BiFunction
//两个参数 一个返回值
@FunctionalInterface
public interface BiFunction<T, U, R> {
	
    R apply(T t, U u);

    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));
    }
}
public static void main(String[] args) {

    BiFunction<Integer, Integer, Integer> biFunction = (n1, n2) -> n1 + n2;
    System.out.println(biFunction.apply(1, 2));
}

//3
BinaryOperator
//两个参数 一个返回值 参数和返回值类型相同
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {

    public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
        Objects.requireNonNull(comparator);
        return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
    }

    public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
        Objects.requireNonNull(comparator);
        return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
    }
}
public static void main(String[] args) {
		
    BinaryOperator<Integer> binaryOperator = (n1, n2) -> n1 + n2;
    System.out.println(binaryOperator.apply(1, 2));
}

//3
4.方法引用

在lambda表达式中,当方法体中只有一个方法调用且方法参数是箭头左边的参数

时,可以将lambda表达式缩写为方法引用,使用方法引用可以避免生成lambda$0

函数优化性能

eg.

//缩写为方法引用
Consumer<Integer> consumer1 = c -> System.out.println(c);
Consumer<Integer> consumer2 = System.out::println;
consumer1.accept(1); //1
consumer2.accept(1); //1
public class Person {

    private String name;

    private int age;

    private String gender;

    public Person() {

    }

    public Person(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    //静态方法
    public static void eat(String food){
        System.out.println("人在吃" + food + "...");
    }

    //普通方法
    public int play(String ball){
        System.out.println(this.name + "在打" + ball + "...");
        return this.age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }
}
//1.静态方法 方法引用 使用类名::方法
Consumer<String> consumer = Person::eat;
consumer.accept("苹果");

//2.普通方法 方法引用
//1)使用实例::方法
Person person = new Person("张三", 18, "男");
Supplier<String> supplier = person::toString;
System.out.println(supplier.get());

//2)使用类名::方法
BiFunction<Person, String, Integer> biFunction = Person::play;
System.out.println(biFunction.apply(person, "篮球"));

//3.构造函数方法引用 类名::new
Supplier<Person> supplier1 = Person::new;
System.out.println(supplier1.get());

/*
人在吃苹果...
Person{name='张三', age=18, gender='男'}
张三在打篮球...
18
Person{name='null', age=0, gender='null'}
*/

注意:

在调用类中普通成员方法时,会将调用者作为参数传入this

在这里插入图片描述

5.变量引用
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
//list = null; //lambda表达式中引用外部的变量必须被final 无法进行修改
Consumer<String> consumer = s -> System.out.println(s + list);
consumer.accept("list:");

//list:[1,2]

二、Stream流式编程

整个流操作就是一条流水线,将元素放在流水线上一个个地进行处理

接口继承关系:

在这里插入图片描述

1.创建流
数据源类型方法
集合Collection.stream / parallelStream
数组Arrays.stream
数值IntStream / LongStream / DoubleStream.range / rangeClosed
Random.ints / longs / doubles
自定义Stream.generate / iterate
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);

//1.从集合创建流
System.out.println("list stream: " + list.stream().collect(Collectors.toList()));
System.out.println("list parallelStream: " + list.parallelStream().collect(Collectors.toList()));
System.out.println("----------------------------------------------");

//2.从数组创建流
System.out.println("array stream: " + Arrays.toString(Arrays.stream(new int[]{1, 2, 3}).toArray()));
System.out.println("----------------------------------------------");

//3.创建数值流
System.out.println("intStream of :" + Arrays.toString(IntStream.of(1, 2, 3).toArray()));
//range [) rangeClosed []
System.out.println("intStream range :" + Arrays.toString(IntStream.range(1, 10).toArray()));
System.out.println("intStream rangeClosed :" + Arrays.toString(IntStream.rangeClosed(1, 10).toArray()));
System.out.println("----------------------------------------------");

//4.Random创建流 需要短路操作需要短路操作(eg.设置个数) 否则会一直创建
Random random = new Random();
System.out.println("random ints :" + Arrays.toString(random.ints().limit(10).toArray()));
System.out.println("----------------------------------------------");

//5.自定义流 需要短路操作
System.out.println("stream generate :" + Arrays.toString(Stream.generate(random::nextInt).limit(10).toArray()));
System.out.println("stream iterate :" + Arrays.toString(Stream.iterate(1, n -> n * 2).limit(10).toArray()));

/*
list stream: [1, 2]
list parallelStream: [1, 2]
----------------------------------------------
array stream: [1, 2, 3]
----------------------------------------------
intStream of :[1, 2, 3]
intStream range :[1, 2, 3, 4, 5, 6, 7, 8, 9]
intStream rangeClosed :[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
----------------------------------------------
random ints :[2062767666, 1550545935, 2043182851, -1626969904, -393174629, -1303175049, 1427478572, 1595123337, -317670513, 748686049]
----------------------------------------------
stream generate :[1315597540, -811133039, -599412873, -876639279, -205436262, -1114456430, 1742542673, 148824684, -1706310645, 1880649223]
stream iterate :[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
*/
2.中间操作和终止操作

中间操作返回值仍然为流,分为:

  • 无状态操作:不依赖其他操作
  • 有状态操作:需要在其他操作计算完毕后执行
方法
无状态map / mapToXxx
flatMap / flatMapToXxx
filter
peek
unordered
有状态distinct
sorted
limit / skip
String str = "hello world";

//打印字符串中每个单词的长度
System.out.println("map:");
Stream.of(str.split(" ")).map(s -> s.length()).forEach(System.out::println);
System.out.println("----------------------------------------------");

//打印字符串中的每一个单词
//intStream、longStream等不是Stream的子类 需要调用boxed方法进行装箱
System.out.println("flatMap:");
Stream.of(str.split(" ")).flatMap(s -> s.chars().boxed()).forEach(s -> {
    System.out.print((char)s.intValue());
});
System.out.println("\n----------------------------------------------");

//打印字符串中所有单词中的'l'字符
//filter过滤出满足条件的元素
System.out.println("filter:");
Stream.of(str.split(" ")).flatMap(s -> s.chars().boxed()).filter(s -> s == 'l').forEach(s -> {
    System.out.print((char)s.intValue());
});
System.out.println("\n----------------------------------------------");

//用于Debug 是一个中间操作
System.out.println("peek:");
Stream.of(str.split(" ")).peek(System.out::println).forEach(System.out::println);
System.out.println("\n----------------------------------------------");

//将前面的计算结果去重
System.out.println("distinct:");
Stream.of(str.split(" ")).flatMap(s -> s.chars().boxed()).distinct().forEach(s -> {
    System.out.print((char)s.intValue());
});
System.out.println("\n----------------------------------------------");

//将前面的计算结果排序
System.out.println("sorted:");
Stream.of(str.split(" ")).flatMap(s -> s.chars().boxed()).sorted().forEach(s -> {
    System.out.print((char)s.intValue());
});
System.out.println("\n----------------------------------------------");

//将跳过指定数目的元素
System.out.println("skip:");
Stream.of(str.split(" ")).flatMap(s -> s.chars().boxed()).skip(1).forEach(s -> {
    System.out.print((char)s.intValue());
});

/*
map:
5
5
----------------------------------------------
flatMap:
helloworld
----------------------------------------------
filter:
lll
----------------------------------------------
peek:
hello
hello
world
world

----------------------------------------------
distinct:
helowrd
----------------------------------------------
sorted:
dehllloorw
----------------------------------------------
skip:
elloworld
*/

终止操作分为:

  • 短路操作:无需等待所有结果计算完即可关闭流
  • 非短路操作
方法
短路forEach / forEachOrdered
collect / toArray
reduce
min / max / count
非短路findFirst / findAny
allMatch / anyMatch / noneMatch

String str = "hello world";

//对于并行流 forEach输出会乱序 forEachOrdered保证顺序
System.out.println("forEach:");
str.chars().parallel().forEach(c -> System.out.print((char) c));
System.out.println("\n----------------------------------------------");
System.out.println("forEachOrdered:");
str.chars().parallel().forEachOrdered(c -> System.out.print((char) c));
System.out.println("\n----------------------------------------------");

//将结果收集为集合输出
System.out.println("collect:");
List<String> words = Stream.of(str.split(" ")).collect(Collectors.toList());
System.out.println(words);
System.out.println("----------------------------------------------");

//对元素进行处理 返回Optional对象
System.out.println("reduce:");
Optional<String> reduce = Stream.of(str.split(" ")).reduce((s1, s2) -> s1 + "|" + s2);
//使用get()获取结果可能会抛出异常  推荐使用orElse()出现异常返回初始值""
//System.out.println(reduce.get());
System.out.println(reduce.orElse(""));
//简写方式
System.out.println(Stream.of(str.split(" ")).reduce("", (s1, s2) -> s1 + "|" + s2));
System.out.println("----------------------------------------------");

//找出字符串中最长的单词
System.out.println("max:");
Optional<String> max = Stream.of(str.split(" ")).max((o1, o2) -> o1.length() - o2.length());
System.out.println(max.orElse(""));
System.out.println("----------------------------------------------");

//找到任何一个终止 找到第一个终止
System.out.println("findAny、findFirst:");
Random random = new Random();
OptionalInt any = random.ints().findAny();
OptionalInt first = random.ints().findFirst();
System.out.println(any.orElse(0));
System.out.println(first.orElse(0));
System.out.println("----------------------------------------------");

//allMatch 所有元素满足条件
//anyMatch 任意元素满足条件
//noneMatch 所有元素都不满足条件
System.out.println("allMatch、anyMatch、noneMatch:");
System.out.println(IntStream.rangeClosed(1, 10).allMatch(i -> i == 1));
System.out.println(IntStream.rangeClosed(1, 10).anyMatch(i -> i == 1));
System.out.println(IntStream.rangeClosed(1, 10).noneMatch(i -> i == 0));

/*
forEach:
wo rehldlol
----------------------------------------------
forEachOrdered:
hello world
----------------------------------------------
collect:
[hello, world]
----------------------------------------------
reduce:
hello|world
|hello|world
----------------------------------------------
max:
hello
----------------------------------------------
findAny、findFirst:
1453443251
654947878
----------------------------------------------
allMatch、anyMatch、noneMatch:
false
true
true
*/

惰性求值:如果对流的处理没有终止操作则不会执行任何操作

class A {

    public static void print(int num) {
        System.out.println("打印" + num + "...");
    }
}

IntStream.rangeClosed(1, 10).peek(A::print).forEach(System.out::println);
System.out.println("-----------------------------------");
System.out.println("惰性求值:");
IntStream.rangeClosed(1, 100).peek(A::print);

/*
打印1...
1
打印2...
2
打印3...
3
打印4...
4
打印5...
5
打印6...
6
打印7...
7
打印8...
8
打印9...
9
打印10...
10
-----------------------------------
惰性求值:
*/
3.并行流

多次调用parallel / sequential 以后面的为准

并行使用的线程池为ForkJoinPool.commonPool,默认线程数为当前机器的核数

class B {

    public static void show(int num) {
        System.out.println(Thread.currentThread().getName() + "打印" + num + "...");
    }
}

//设置线程数
//System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "10");
System.out.println("count :" + IntStream.rangeClosed(1, 10)
        .parallel().peek(B::show)
        //.sequential().peek(B::show)
        .count());

/*
main打印7...
ForkJoinPool.commonPool-worker-1打印3...
main打印6...
ForkJoinPool.commonPool-worker-1打印4...
ForkJoinPool.commonPool-worker-3打印2...
ForkJoinPool.commonPool-worker-7打印10...
ForkJoinPool.commonPool-worker-6打印1...
ForkJoinPool.commonPool-worker-4打印8...
ForkJoinPool.commonPool-worker-2打印9...
ForkJoinPool.commonPool-worker-5打印5...
count :10
------------------------------
main打印1...
main打印1...
main打印2...
main打印2...
main打印3...
main打印3...
main打印4...
main打印4...
main打印5...
main打印5...
main打印6...
main打印6...
main打印7...
main打印7...
main打印8...
main打印8...
main打印9...
main打印9...
main打印10...
main打印10...
count :10
*/

推荐使用自己的线程池,默认线程池可能被其他程序使用产生阻塞

ForkJoinPool forkJoinPool = new ForkJoinPool(10);
forkJoinPool.submit(() -> {
    System.out.println(IntStream.rangeClosed(1, 10)
            .parallel().peek(B::show)
            .count());
});

TimeUnit.SECONDS.sleep(5);

/*
ForkJoinPool-1-worker-4打印2...
ForkJoinPool-1-worker-1打印10...
ForkJoinPool-1-worker-6打印8...
ForkJoinPool-1-worker-9打印7...
ForkJoinPool-1-worker-8打印1...
ForkJoinPool-1-worker-11打印9...
ForkJoinPool-1-worker-15打印6...
ForkJoinPool-1-worker-13打印5...
ForkJoinPool-1-worker-2打印3...
ForkJoinPool-1-worker-4打印4...
10
*/
4.收集器
Person person1 = new Person("张三", 18, "男");
Person person2 = new Person("李四", 19, "男");
Person person3 = new Person("王五", 21, "男");
Person person4 = new Person("李华", 25, "女");

ArrayList<Person> list = new ArrayList<>();
list.add(person1);
list.add(person2);
list.add(person3);
list.add(person4);

//统计最大值、最小值、平均值、数量和总和
System.out.println("summarizingInt:");
IntSummaryStatistics summaryStatistics = list.stream().collect(Collectors.summarizingInt(Person::getAge));
System.out.println(summaryStatistics);
System.out.println("-----------------------------------");

//按照性别分块 分块是一种特别的分组(只有两组)
System.out.println("partitioningBy:");
Map<Boolean, List<Person>> genderPartitions = list.stream().collect(Collectors.partitioningBy(p -> p.getGender() == "男"));
System.out.println(genderPartitions);
System.out.println("-----------------------------------");

//按照年龄分组
System.out.println("groupingBy:");
Map<Integer, Long> ageGroups = list.stream().collect(Collectors.groupingBy(Person::getAge, Collectors.counting()));
System.out.println(ageGroups);

/*
summarizingInt:
IntSummaryStatistics{count=4, sum=83, min=18, average=20.750000, max=25}
-----------------------------------
partitioningBy:
{false=[Person{name='李华', age=25, gender='女'}], true=[Person{name='张三', age=18, gender='男'}, Person{name='李四', age=19, gender='男'}, Person{name='王五', age=21, gender='男'}]}
-----------------------------------
groupingBy:
{18=1, 19=1, 21=1, 25=1}
*/
5.原理分析
//中间操作
IntStream intStream = new Random().ints().limit(10)
    	//无状态
        .peek(i -> {
            System.out.println("peek: " + i);
        })
    	//有状态
        //.sorted()
    	//无状态    
    	.filter(i -> {
            System.out.println("filter: " + i);
            return i > 0;
        });
//终止操作
intStream.count();

在这里插入图片描述

在这里插入图片描述

所有操作都是链式调用,每一个中间操作返回一个流,流中有一个属性

sourceStage指向Head,整个链路类似

Head -> nextStage -> nextStage -> ··· -> null

有状态中间操作依赖于前面计算的结果,会把无状态操作分隔开
在这里插入图片描述

parallel()、sequetial()也是中间操作,但它们不返回流对象,只修改sourceStage

的parallel字段

//中间操作
IntStream intStream = new Random().ints().limit(10)
        .parallel()
        //无状态
        .peek(i -> {
            System.out.println(Thread.currentThread().getName() + "peek: " + i);
        })
        //有状态
        .sorted()
        //无状态
        .filter(i -> {
            System.out.println(Thread.currentThread().getName() + "filter: " + i);
            return i > 0;
        });
//终止操作
intStream.count();

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值