[Lambda操作]1.filter 2.Comparator 3.flatMap 4.map 5.Predicate 6.findAny 7.Consumer 8.多重排序 9.分组 10.peek

 

1.从HashMap中筛选出小于4的(filter),筛选出的元素列表从小到大排序(sorted)

        Map<String, Integer> m = Maps.newHashMap();
		m.put("1", 1);
		m.put("6", 6);
		m.put("2", 2);
		m.put("4", 4);
		m.put("5", 5);

		List<String> list = m.keySet()
				.stream()
				.filter(k -> { // 过滤满足条件的key列表
					Integer num = m.get(k);
					return num != null && num < 4;
				})
				.sorted(Comparator.reverseOrder()) // 从大到小排序
				.collect(Collectors.toList());

		if (list.size() == 0) {
			System.out.println("-1");
		} else {
			System.out.println(list.get(0));
		}


/*
2
 */

2.Comparator.comparingInt // 将List中的元素按照指定规则进行从小到大排序。注意后面那个Int,

但是发现写成:Comparator.comparing 也能正常运行。

代替的是:(a, b) -> a.getScore() - b.getScore() 这种写法,我觉得反而不好读了。

public class Main {
    public static void main(String[] args) {
        List<Student> students = Lists.newArrayList(new Student(10), new Student(20), new Student(5));
        Collections.sort(students, Comparator.comparingInt(Student::getScore));

        System.out.println(students);
    }

    @Data
    @AllArgsConstructor
    private static class Student {
        private int score;
    }
}

3.根据一个List,里面又是一个List归并为一个大的List(flatMap、map)

例子1:
    /**
     * 得到这个玩家所有派遣的格斗家id Set
     *
     * @param role
     * @return
     */
    private Set<String> getHaveDispatchHeroIdSet(Role role) {
        Map<String, RoleRewardTaskItem> allTaskItem = getAllTaskItem(role);
        Set<String> heroIdSet = allTaskItem.values()
                .stream()
                // 对List再次Stream,接着再map可以实现多个List的归并
                .flatMap(c -> c.getHeroes().stream())
                .map(c -> c.getId())
                .collect(Collectors.toSet());
        return heroIdSet;
    }


例子2:

        List<PlayerEntity> allPlayerEntity = curRankMap.values().stream() // 从排行中拿有效的玩家
                .flatMap(Collection::stream) // 得到新的Stream
                .map(c -> DBOperateGen.getInstance().getPlayerEntity(Long.parseLong(c.getValue()))) // 得到PlayerEntity
                .filter(Objects::nonNull) // 过滤空的
                .collect(Collectors.toList());

再次举例

package org.example.testflatmap;

import com.google.common.collect.Lists;

import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        Integer[][] arr = {{1, 2, 3}, {3, 4, 5, 6}, {3, 4, 5}};
        Set<Integer> set = Arrays.stream(arr)
                .flatMap(c -> Lists.newArrayList(c).stream())
                .collect(Collectors.toSet());
        System.out.println(set);
    }
}

/*
[1, 2, 3, 4, 5, 6]
 */

真实案例:1个人有6个槽位,推荐出工会中有处于喂养中,且没有被别人喂养过的槽位信息。 

4.针对一个列表,传入一个筛选规则(Predicate) 适用于自己制定筛选规则的情况,如需求1是:筛选出等于某个品质的。需求2是筛选出某个等级的,需求3是:筛选出重量>30的。

而stream的filter是一个确定的规则,这个则允许自定义一个规则。

/**
     * 筛选出满足这个等级的item信息
     * @param level
     * @return
     */
    public static QuestLv getQuestLvConfig(int level) {
        Optional<QuestLv> op = GameLogicHelper.getNumericByFilter(QuestLv.class, q -> q.level == level);
        return op.get();
    }

   public static <T> Optional<T> getNumericByFilter(Class<T> clazz, Predicate<T> filter) {
        // 因此读取表非常方便
        List<String> tags = NumericService.getNumericIdList(clazz);
        for (String tag : tags) {
            T obj = NumericService.getNumericById(clazz, tag);
            if (filter.test(obj)) {
                return Optional.ofNullable(obj);
            }
        }
        return Optional.empty();
    }

5.findAny(在指定规则下,找出一个,可以使用OrElse在找不到的时候返回null)

/**
笔记:
1.findAny相比于findFirst,有 短路求值特性,性能略高一点
2.在并行stream下,findAny每次可能返回的结果不同,找到一个就停止,而findFirst则每次都相同
3.在串行模式下,findAny每次返回值也都相同
*/
public class TestFindAny {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 1, 2, 3, 4, 5);
        Integer ret = list.stream()
                .filter(v -> v > 30)
                .findAny()
                .orElse(null);
        System.out.println(ret);
    }
}

/*
null
 */

6.Consumer(有多个行为,行为不确定的情况下,将行为参数化)

同时,使用Optional.ofNullable来避免空指针

public class TestConsumer {
    private static class Test {
        public void f() {
            System.out.println("f called!!!");
        }
    }

    public static void handler(Test test, Consumer<Test> consumer) {
        //在test参数有值的情况下
        //consumer接受一个lambda表达式
        Optional.ofNullable(test)
                .ifPresent(t1 -> consumer.accept(t1));
    }

    public static void main(String[] args) {
        Test t = new Test();
        // 注意下面第2个参数这个lambda表达式
        handler(t, test -> test.f()); // 等价于 handler(t, T::f);
    }
}

/*
f called!!!
 */

7)传入一个规则,并且获得返回值(Function)

public class TestConsumer {
    private static class Test {
        public int g() {
            return 1;
        }
    }
 
    public static void handler(Test test, Consumer<Test> consumer) {
        //有值时执行一个consumer
        Optional.ofNullable(test)
                .ifPresent(t1 -> consumer.accept(t1));
    }
 
    public static void main(String[] args) {
        //等价于Function<Test, Integer> fun = Test::g;
        Function<Test, Integer> fun = t-> t.g(); 

        Integer g = fun.apply(new Test());
        System.out.println(g);
    }
}

8)存储一个类的实例(Supplier)

但实际上,xxx::new其实是一个方法引用。

class Test {
    private int num = 1;
 
    public int getNum() {
        return num;
    }
 
    public void setNum(int num) {
        this.num = num;
    }
 
    @Override
    public String toString() {
        return "Test{" +
                "num=" + num +
                '}';
    }
}
 
public class TestSupplier {
    public Supplier<Test> s = Test::new; 
 
    public static void main(String[] args) {
        TestSupplier test = new TestSupplier();
        Test t = test.s.get();
        t.setNum(100);
 
        System.out.println(t);
    }
}
 
/*
Test{num=100}
 */

9)多重排序 // 默认从小到大,因此加上反转

package org.example.testSort;

import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<A> list = Lists.newArrayList(
                new A(1, 2, 3),
                new A(1, 3, 2),
                new A(2, 3, 1),
                new A(1, 10, 1),
                new A(4, 1, 1),
                new A(4, 1, 1),
                new A(4, 2, 0),
                new A(3, 100, 100)
        );

        // 按照a,b,c的先后依次进行排序
        // 在sort的最后调用reversed
        list = list.stream()
                .sorted(Comparator.comparingInt(A::getA).thenComparingInt(A::getB).thenComparingInt(A::getC).reversed())
                .collect(Collectors.toList());


        System.out.println(list);
    }
}

@Data
@AllArgsConstructor
class A {
    private int a;
    private int b;
    private int c;
}

/*
[A(a=4, b=2, c=0), A(a=4, b=1, c=1), A(a=4, b=1, c=1), A(a=3, b=100, c=100), A(a=2, b=3, c=1), A(a=1, b=10, c=1), A(a=1, b=3, c=2), A(a=1, b=2, c=3)]
 */

多重排序真实案例:在线、剩余次数、玩家id

10)方法引用 XXX::onHumanDead

XXX.class

public onHumanDead(SceneRole killer){
}

XXX::onHumanDead

这种看着是传递了一个参数,

但是Function2{
void apply(T1 p1, T2 p2);

}


看着是2个参数,正是因为这里需要一个XXX实例,因此this就是apply的第一个参数。

11)BiPredicate定义一个规则(比如:采集物品,有的能采集,有的不能采集,那就可以设置一个采集规则)

package org.example.testBiPredicate;
 
import java.util.function.BiPredicate;
 
public class Main {
    public static void main(String[] args) {
        A a = new A();
        a.setCheck(a::checkMethodImpl);
 
        System.out.println(a.isOk(18, "jianan"));
        System.out.println(a.isOk(18, "jianan1"));
    }
 
 
    private static class A {
        /**
         * 规则
         */
        private BiPredicate<Integer, String> check;
 
        public boolean isOk(Integer age, String s) {
            return check != null && check.test(age, s);
        }
 
        public void setCheck(BiPredicate<Integer, String> check) {
            this.check = check;
        }
 
        /**
         * 指定下满足规则的实现
         *
         * @param age
         * @param s
         * @return
         */
        public boolean checkMethodImpl(Integer age, String s) {
            if (age == 18 && s.equals("jianan")) {
                return true;
            }
            return false;
        }
    }
}
 
/*
true
false
 */

12)Collectors.groupingBy  // 进行分组,返回值是Map<Integer, List<Integer>> 是一个map。

应用:比如游戏中有3个区域,每个区域有5个刷新点,随机一个刷新点进行刷新,那么就可以在读取配置时使用这个分组,提前设置好数据。

注意:由于开始不知道这个功能,因此我使用的Map<Integer, List<xxx>> 自己去搞得,实际上分组的话,必然每一个组肯定是一个List。

package org.example.testGroupingBy;

import com.google.common.collect.Lists;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<Pair<Integer, String>> list = Lists.newArrayList(
                new ImmutablePair(1, "1"), 
                new ImmutablePair(1, "11"),
                new ImmutablePair(2, "2"),
                new ImmutablePair(3, "3"),
                new ImmutablePair(3, "33"),
                new ImmutablePair(2, "22"),
                new ImmutablePair(3, "333"));

        Map<Integer, List<Pair<Integer, String>>> map = list.stream().collect(Collectors.groupingBy(Pair::getLeft));

        System.out.println(map);
    }
}

/*
{1=[(1,1), (1,11)], 2=[(2,2), (2,22)], 3=[(3,3), (3,33), (3,333)]}
 */

例子2:分组、Objects::nonNull、flatMap综合使用

package org.example.testAnyMatch;

import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<Student> students = Lists.newArrayList(
                new Student(10, "a"),
                new Student(20, "b"),
                new Student(5, "c"),
                new Student(5, "d"),
                null
        );

        // 先按照成绩分组
        Map<Integer, List<Student>> groupMap = students.stream()
                .filter(Objects::nonNull) // 先把空的过滤掉
                .collect(Collectors.groupingBy(Student::getScore));

        // 分组后,所有的人再放一
        List<Student> newStuds = groupMap.values().stream()
                .flatMap(c -> c.stream())
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        System.out.println(newStuds);

    }

    @Data
    @AllArgsConstructor
    private static class Student {
        private int score;
        private String desc;
    }
}

/*
[Main.Student(score=20, desc=b), Main.Student(score=5, desc=c), Main.Student(score=5, desc=d), Main.Student(score=10, desc=a)]
 */

13)anyMatch // 是否在一个List中有任何满足的指定条件的元素,返回值是boolean。

比如:是否队伍中所有人都有活动次数,没有的话,没必要到下一步了。

List<Student> students = Lists.newArrayList(new Student(10), new Student(20), new Student(5));
boolean b = students.stream().anyMatch(c -> c.getScore() <= 3);
System.out.println(b);

14)limit的使用案例

package org.example.testHashMap;

import com.google.common.collect.Lists;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author jianan
 * @date 2021/7/8 11:58:51
 */
public class TestHashMap {
    public static void main(String[] args) {

        List<String> list = Lists.newArrayList("a", "b", "c", "d", "e", "a");

        List<String> newList = list.stream()
                .sorted((a, b) -> {
                    System.out.println("sort");
                    return a.compareTo(b);
                })
                .map(str -> {

                    System.out.println("--str:" + str);
                    String newStr = str + "1";

                    return newStr;

                })
                .limit(2)
                .collect(Collectors.toList());


        System.out.println(newList);
    }
}

/*
sort
sort
sort
sort
sort
sort
sort
sort
--str:a
--str:a
[a1, a1]
 */

在list这是数据源,比如:有50个工会成员,接着需要推荐前10名。那加上limit后,其实就只计算2个。但是sort的话,肯定会遍历所有的人,从而:导致所有的涉及到的数据被加载。

15.今天看到队友写的stream用到了peek,我开始以为是移除元素,其实不是

import com.google.common.collect.Lists;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

public class Main {
	public static void main(String[] args) throws InterruptedException {
		List<AtomicInteger> list = Lists.newArrayList(new AtomicInteger(1), new AtomicInteger(2));

		// 如果写成: list.stream().peek(c -> c.set(c.get() * 2)); 则最终不生效,因为不是最终操作
		list.stream().peek(c -> c.set(c.get() * 2)).collect(Collectors.toList());

		// 或者 写成:list.forEach(c -> c.set(c.get() * 2))
		list.stream().forEach(c -> c.set(c.get() * 2));

		System.out.println(list);
	}
}

也就是peek和forEach相比,就是:peek不是最终操作,也就是在java的Stream中,为了性能,如果不执行最终操作,其实是不会生效。

forEach是最终操作。

16.stream、min、Optional、orElse

		List<Integer> list = Lists.newArrayList();
		Integer num = list.stream()
				.min(Integer::compareTo) // 排序后,找出最小值
				.orElse(-1);       // 如果list为空,则返回-1
		System.out.println(num);

17.Collectors.toMap

package org.example.toMap;

import com.google.common.collect.Lists;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<Data> dataList = Arrays.asList(
                new Data(1, Lists.newArrayList(1, 2, 3)),
                new Data(1, Lists.newArrayList(2, 3, 4, 5)),
                new Data(2, Lists.newArrayList(5, 6, 7, 8, 9)));

        // 可以看出来v1和v2的值其实取决于 Map中第2个元素的类型
        Map<Integer, List<Integer>> ret = dataList.stream().collect(Collectors.toMap(Data::getId, Data::getList, (v1, v2) -> {
            // 这里表示:遇到的key相同时怎么处理
            v1.addAll(v2);

            return v1;
        }));

        System.out.println(ret);
    }

    private static class Data {
        private int id;

        private List<Integer> list;

        public Data(int id, List<Integer> list) {
            this.id = id;
            this.list = list;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public List<Integer> getList() {
            return list;
        }

        public void setList(List<Integer> list) {
            this.list = list;
        }

        @Override
        public String toString() {
            return "Data{" +
                    "id=" + id +
                    ", list=" + list +
                    '}';
        }
    }
}

/*
{1=[1, 2, 3, 2, 3, 4, 5], 2=[5, 6, 7, 8, 9]}
 */

项目中toMap的例子:

	//toMap
		// k:其实还是列表中的元素,返回Map的key取哪一部分
		// v: 其实还是列表中的元素,返回Map的key取哪一部分
		// 第三个: 类型是v返回的那个类型,函数体是:就是:报名当前出现了相同的key后,如何处理。 // 本例是:List如何合并
		Map<Integer, List<Integer>> id2ids = msg.getHeroCostList().stream()
				.collect(Collectors.toMap(k -> k.getMainId(), v -> v.getConsIdsList(), (k1, k2) -> {
					k1.addAll(k2);
					return k1;
				}));

18.BinaryOperator实现自定义Map操作

package org.example.testBinaryOperator;

import com.google.common.collect.Maps;

import java.util.Map;
import java.util.function.BinaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {
	public static void main(String[] args) {
		Map<Integer, Integer> map1 = Maps.newHashMap();
		map1.put(1, 1);
		map1.put(2, 2);

		Map<Integer, Integer> map2 = Maps.newHashMap();
		map2.put(2, 2);


		Map<Integer, Integer> merge = merge(map1, map2, (x, y) -> x + y);
		System.out.println(merge);
	}

	public static <K, V> Map<K, V> merge(Map<K, V> map1, Map<K, V> map2, BinaryOperator<V> operator) {
		return Stream.concat(map1.entrySet().stream(), map2.entrySet().stream())
				.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, operator));
	}
}

/*
{1=1, 2=4}
 */

19.对List分组 // fork-join

package org.example.portition;

import com.google.common.collect.Lists;

import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = Lists.newArrayList(1, 5, 4, 3, 2, 6, 7, 8, 9);

        // 分割
        List<List<Integer>> partitionList = Lists.partition(list, 3);

        System.out.println(partitionList);
    }
}

/*
[[1, 5, 4], [3, 2, 6], [7, 8, 9]]
 */

理解:

就是我们同步执行,但是有时一些任务可以并行计算,计算完后合并一下。

有点master-worker的感觉。

比如: 一帧内所有单位的更新,我们发现有些可以多线程计算,此时可以使用CompletableFuture进行组织整个任务的拆分,就可以用这个api做拆分,之后使用alllOf和join完成任务的编排。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值