jdk8自带了一个jjs的脚本,如果是windows安装,可以在自己安装好的jdk目录下看到有一个jjs.exe的脚本

如果是mac则可以在jdk安装目录下看到有一个jjs的可执行脚本

然后我们写一个js脚本,控制台输出一句话试试,这里注意除了输出语句不是console.log其他的都是一样的

print('hello');

然后使用命令执行这个脚本

jjs hello.js

lambda表达式

当我们在编写一个匿名对象时,需要在new右边写上方法体,如下

Comparator<Integer> a = new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o1.compareTo(o2);
    }
};

而这时候,可以看到里面是只有一个方法的,就叫compare,返回值是int类型,这时候我们就可以使用lambda表达式,因为这里就一个方法,我就不需要知道你叫什么方法名,你肯定是调用这个叫做compare的方法,所以我们可以直接写出参数,和方法体

Comparator<Integer> a = (Integer o1,Integer o2) -> {
    return o1.compareTo(o2);
};

这里注意,在左边接收的时候是指定了范型是Integer类型,所以右边肯定是两个Integer,不可能是别的,所以也可以直接省略

Comparator<Integer> a = (o1, o2) -> {
    return o1.compareTo(o2);
};

最后注意这里方法体里面只有一条语句,并且方法的返回值就是int,所以这里也不用写,因为我就一条语句,肯定就是返回这个语句,不需要写return

Comparator<Integer> a = (o1, o2) -> o1.compareTo(o2);

方法引用

创建的这个匿名对象所调用的方法在另一个类中刚好有功能相同的方法则可以直接通过类名::方法名的方式调用

但是其实程序并不能识别到你引用的方法是不是和当前方法的功能是否一致,它只会识别你要引用的方法是不是返回值和参数类型是否一致,来举个例子

我现在自定义一个接口如下

public interface Mylambda {
    void test(String s);
}

然后我们在主方法中创建一个这个接口的匿名函数

Mylambda mylambda = new Mylambda() {
    @Override
    public void test(String s) {
      s = s+"1";  
    }
};

这里可以看到我在里面随便写了一个字符串的拼接

然后我们在创建一个静态的方法,和接口的test方法的返回值和参数列表一致

也就是没有返回值和一个字符串入参

public static void hello(String s){
    System.out.println("调用了test。hello");
}

然后我们就把刚刚创建的匿名函数改造成这个方法的引用

Mylambda mylambda = test::hello;

这样虽然改变了我们之前创建 的匿名函数的功能,但是这个写法不会报错,也就是说我从一个字符串拼接转成了输出一个字符串语句,虽然这个引用是不对的,但是编译器不会报错,因为它只识别返回值是否相同和参数是否相同,如果一致那他就认为是同一个方法就可以进行引用。

当然上面是一个错误的例子,只是希望更好的说明什么是方法的引用。也就是要创建一个匿名函数时,可以引用另一个静态或非静态方法来替换。

下面举一个正确的例子

首先我们创建一个匿名对象

Comparator<Integer> comparator = new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return Integer.compare(o1,o2);
    }
};

然后由于这个方法和Integer.compare(o1,o2)这个静态方法的功能是一样的,所以我们可以直接引用这个Integer的compare方法

Comparator<Integer> comparator = Integer::compare;

Stream API

stream流可以对集合数组进行操作,最后返回结果

stream流的过滤 filter

首先如果有一个需求,需要在一个集合中塞选出大于50的数,然后放到另一个集合中,那么我们最原始的方法应该是如下这样

ArrayList<Integer> integers1 = new ArrayList<>();
List<Integer> integers = new ArrayList<>();
integers.add(1);
integers.add(10);
integers.add(60);
integers.add(70);
integers.add(80);

for (Integer integer : integers) {
    if (integer>50) {
        integers1.add(integer);
    }
}

而这时候我们使用流过滤的话就可以把循环变为一条语句

ArrayList<Integer> integers1 = new ArrayList<>();
List<Integer> integers = new ArrayList<>();
integers.add(1);
integers.add(10);
integers.add(60);
integers.add(70);
integers.add(80);
integers.stream().filter(integer -> integer > 50).forEach(integers1::add);

stream流的切片 limit

还是刚刚的数据,如果我们只想要三个数据应该怎么做呢,只需要在过滤完成后进行limit,然后再添加就好了,这样最终就只能添加指定的个数

ArrayList<Integer> integers1 = new ArrayList<>();
List<Integer> integers = new ArrayList<>();
integers.add(1);
integers.add(10);
integers.add(60);
integers.add(70);
integers.add(80);
integers.stream().filter(integer -> integer > 50).limit(2).forEach(integers1::add);

stream流的跳过 skip

这个跟切片有点像,指定多少个元素跳过,我们来试试前面的2个跳过不保存

ArrayList<Integer> integers1 = new ArrayList<>();
List<Integer> integers = new ArrayList<>();
integers.add(1);
integers.add(10);
integers.add(60);
integers.add(70);
integers.add(80);
integers.stream().filter(integer -> integer > 50).skip(2).forEach(integers1::add);

这样我们就只能获取到两个数之后的数了

stream流的去重 distinct

List<String> strings = new ArrayList<>();
strings.add("马云");
strings.add("马云");
strings.add("马云");
strings.stream().distinct().forEach(System.out::println);

去重会根据hashcode和equals进行判断,也可以对对象进行去重,但是要注意要重写对象的equals方法和hashcode方法才可以去重

List<Emp> emps = new ArrayList<>();
emps.add(new Emp("张三"));
emps.add(new Emp("张三"));
emps.stream().distinct().forEach(System.out::println);

stream流操作每一个值

上面说的过滤是对符合要求的值进行一个操作,但是我们现在的要求是对集合中每一个元素进行操作的话那么使用过滤就多余了,我们可以使用map进行操作

现在我们将集合中所有字符串转大写

List<String> strings = new ArrayList<>();
strings.add("aa");
strings.add("bb");
strings.add("cc");

List<String> strings1 = strings.stream().map(String::toUpperCase).collect(Collectors.toList());

stream流排序sorted

这是自动排序

List<Integer> integers = Arrays.asList(1, 2, 5, 0, -9, -5);
integers.stream().sorted().forEach(System.out::println);

也可以根据自己定义的方法进行排序,例如对对象进行排序

List<Emp> emps = new ArrayList<>();
emps.add(new Emp(4));
emps.add(new Emp(2));
emps.add(new Emp(7));

List<Emp> emps1 = emps.stream().sorted(Comparator.comparingInt(Emp::getAge)).collect(Collectors.toList());

stream流终止操作

终止操作即获取最终的结果,比如上面的foreach

allMatch 匹配结果集是否所有都符合某个规则

比如一个结果集内我们看看所有的对象的年龄是否都大于18

List<Emp> emps = new ArrayList<>();
emps.add(new Emp(17));
emps.add(new Emp(20));
emps.add(new Emp(21));

boolean b = emps.stream().allMatch(emp -> emp.getAge() > 18);
System.out.println(b);  //返回false

anyMatch 结果集中是否有一个符合某个规则

还是刚刚的例子,有没有一个是大于18岁的

List<Emp> emps = new ArrayList<>();
emps.add(new Emp(17));
emps.add(new Emp(20));
emps.add(new Emp(21));

boolean b = emps.stream().anyMatch(emp -> emp.getAge() > 18);
System.out.println(b);  //true

noneMatch 检查是否没有匹配的元素

还是上面的例子,我们检查是否没有大于18岁的,返回肯定是false

List<Emp> emps = new ArrayList<>();
emps.add(new Emp(17));
emps.add(new Emp(20));
emps.add(new Emp(21));

boolean b = emps.stream().noneMatch(emp -> emp.getAge() > 18);
System.out.println(b);  //false

findFirst 返回流操作后的第一个元素

注意,这里返回的是Optional类型,然后使用get就可以获得里面的元素了

Optional<Emp> first = emps.stream().findFirst();
Emp emp = first.get();
System.out.println(emp);

findAny 返回流结果集中任意一个元素

这里要注意!stream流要换成parallelStream并行流,否则使用findAny一直都会返回第一个

List<Emp> emps = new ArrayList<>();
emps.add(new Emp(17));
emps.add(new Emp(20));
emps.add(new Emp(21));

Optional<Emp> first = emps.parallelStream().findAny();
Emp emp = first.get();
System.out.println(emp);

count 返回流结果集中的个数

这个没什么好讲的,就是过滤之后计算个数

List<Emp> emps = new ArrayList<>();
emps.add(new Emp(17));
emps.add(new Emp(20));
emps.add(new Emp(21));

long count = emps.stream().count();
System.out.println(count);

max 返回指定规则中的最大值

这里注意 使用max返回的是Optional 也是要通过get获取原先的元素

List<Emp> emps = new ArrayList<>();
emps.add(new Emp(17));
emps.add(new Emp(20));
emps.add(new Emp(21));

System.out.println(emps.stream().max(Comparator.comparingInt(Emp::getAge)).get());

min 这个应该也不用讲,和max是一样的操作

foreach 迭代

可以遍历流中的每一个元素并进行一定的操作 这个和for是一样的

List<Emp> emps = new ArrayList<>();
emps.add(new Emp(17));
emps.add(new Emp(20));
emps.add(new Emp(21));

emps.stream().forEach(System.out::println);

reduce 归约

当我们想操作一个集合然后获取最终结果时,我们必须在外面定义一个变量,然后将循环出的变量叠加到外部的变量,但是在匿名内部类来说如果你不是一个final类型的变量就是不可以操作的

我们可以使用归约来进行操作,演示一个相加

List<Emp> emps = new ArrayList<>();
emps.add(new Emp(17));
emps.add(new Emp(20));
emps.add(new Emp(21));

Integer integer = emps.stream().map(Emp::getAge).reduce(Integer::sum).get();

收集collect

可以将最终结果转换为我们想要的某个结果集

List<Emp> emps = new ArrayList<>();
emps.add(new Emp(17));
emps.add(new Emp(20));
emps.add(new Emp(21));

emps.stream().filter(emp -> emp.getAge()>18).collect(Collectors.toList());

Optional 类

可以最大限度减少空指针

获取Optional

of

这里要保证传入的对象是非空的,否则会报空指针

Emp emp = new Emp();
Optional<Emp> emp1 = Optional.of(emp);

ofNullable

这里传入的对象可以为空

Emp emp = new Emp();
Optional<Emp> emp1 = Optional.ofNullable(emp);

orElse

如果传入的对象是一个null那么就赋值为括号里的值,否则为原先的值

Emp emp = new Emp();
Optional<Emp> emp1 = Optional.ofNullable(emp);
Emp emp2 = emp1.orElse(new Emp(10));