java8 lambda表达式详解(二)

上一篇文章java8 lambda表达式详解(一)主要讲到了单独表达式和块儿lambda表达式,这篇文章里,会对更多的lambda表达式特性进行讲解!


1 泛型函数式接口

lambda表达式本身不能指定类型参数,所以当然不能是泛型,但是,与lambda表达式关联的函数式接口,是可以使用泛型的!现在考虑这样一种情况,

下面给出代码示例

interface ForMethodInterface {
    void print(List<Integer> integerList);
}

public static void main(String[] args) {
        String test1 = "hello lambda";
        FunctionInterfaceT<String> ft = (test) -> {
            return test.substring(1,3);
        };
        System.out.println(ft.getT(test1));
    }


2 作为参数传递的lambda表达式
上面的例子很容易理解,下面的问题就是,如何更好的利用lambda表达式呢,无论是上一篇文章,还是这里,都是最简单的声明,而封装呢?该怎么做,比如,定义一个方法,参数就是第一个lambda表达式,其实,java8的集合类,都已经引入了此类方法,比如ArrayList

/**
     * 打印lists集合内元素
     * @param args
     */
    public static void main(String[] args) {
        ArrayList<Integer> lists = new ArrayList<Integer>();
        lists.add(1);
        lists.add(2);
        //从前的做法
        for (Integer list : lists){
            System.out.println(list);
        }
        //java8的做法
        lists.forEach((list)-> System.out.println(list));
    }
上面是从前和现在的操作集合的方法,目前java8的集合,已经都新增了这个forEach()方法,这个方法的内部结构为
@Override
    public void forEach(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        final int expectedModCount = modCount;
        @SuppressWarnings("unchecked")
        final E[] elementData = (E[]) this.elementData;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            action.accept(elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }
其实很简单,里面就一个for循环,只不过,循环里执行的动作是类似于这样的,
(list)-> System.out.println(list)
lambda表达式而已.如果想要封装一个类似的方法,只要看这个就可以.

3 lambda表达式和变量捕获

在lamba表达式中,可以访问其作用域意以外的变量,比如,作用域意外的实力或者静态变量等,当这些变量时,会产生一种特殊情况,称为变量捕获,这种情况下,lambda表达式式只能使用实质上final定义的局部变量,实际上final的变量是指在第一次赋值以后,值不在发生变化的量,没有必要显示的将这种变量声明为final.

lambda表达式不能修改外层作用域的局部变量,修改的话会移除其实质上的final属性,从而使这次捕获变量不合法.下面演示一下实质上的final和可变局部变量的区别:

public static void main(String[] args) {
       String test = "hello lambda";
        FunctionInterfaceT fi = (str)->{
            test = test + str;
            return test;
        };
    }
这样编译器是无法通过编译的!

4 方法引用

如果像创建方法引用,可以使用类似这样的语法:ClassName::methonName,类名和方法中间,隔着两个;这种用法与lambda表达式相关,因为其也需要由兼容的函数式接口构成的目标类上下文:

public interface ForStaticUse {
    String subString(String str);
}

public class LambdaS2 {

    public static String sunStr(String str){
        return str.substring(0,3);
    }
}

public class MyStaticUseDemo {

    private static String subStr(ForStaticUse fsu,String str){
        return fsu.subString(str);
    }

    public static void main(String[] args) {
        String test = "hello lambda";
        String outStr;
        outStr = subStr(LambdaS2::sunStr,test);
        System.out.println(outStr);
    }
}


5 预定义的函数式接口
除了自己定义函数式接口以外,java提供了一些预定义的函数式接口.这样我们就不需要大量的去定义函数式接口了!接口的定义在
import java.util.function
下面说明几个重要的函数式接口:

@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {

    /**
     * 返回一元操作运算,其实只是返回传进来的值
     * @param <T> the type of the input and output of the operator
     * @return a unary operator that always returns its input argument
     */
    static <T> UnaryOperator<T> identity() {
        return t -> t;
    }
}
类似的还有,BinaryOperator<T>对类型为T的两个对象应用操作,结果类型也为T,方法为apply()

Consumer<T>,对类型为T的对象进行操作,包含的方法为accept();

Function<T,R>,对类型为T的对象操作,结果是R类型的返回值,包含的方法为accept();


其他的还有很多,不在这里一一列举,其实,想要让lambda表达式,真正的融入到自己的体系中,是需要不断的练习,不断的思考的!要不,只能是徒有其表!


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值