Java 8:如何在JoinRowSets上使用lambda表达式?

时间:2014-09-17 14:30:25

标签: java lambda java-8

我正在开发一个将在我公司的某些产品中使用的功能,因此我无法获得特定于产品的代码。

我将2个查询的结果存储在2个JoinRowSet个对象上(我必须使用JoinRowSet,因为我必须在以后加入其他查询的结果)。然后,我需要与那些JoinRowSet相交,但我不知道他们“属于”哪个类(我不知道查询是否会返回人物,联系人,部门或任何其他东西)。我被告知我应该使用lambda表达式来做到这一点,但我发现了一些问题。

我已将JoinRowSet中的一个转换为Collection(我不知道如何直接在JoinRowSet上使用lambda表达式),然后我循环遍历其中一个JoinRowSet对于此JoinRowSet的每一列,我想获取初始Collection上与该列具有相同值的记录。但是,由于我不知道数据的类,我不能做u.getAge()之类的事情,因为我没有属性名称。

这是我的方法:

public static void testLambdas() throws SQLException {

    ... //set the needed stuff to connect to database and query data 

    JoinRowSet jrs1 = ... //result from query 1
    JoinRowSet jrs2 = ... //result from query 2
    Collection<Row> jrs2Collection = (Collection<Row>) jrs2.getRowSets();//collection to use on lambda expression

    while (jrs1.next()) {

        ResultSetMetaData metadata = jrs1.getMetaData();
        for (int j = 1; j <= metadata.getColumnCount(); j++) {

            String dataType = metadata.getColumnTypeName(j);
            Object colValue = null;

            if (dataType.equals("NUMBER")) {
                colValue = jrs1.getBigDecimal(j);               
            } else if (dataType.equals("VARCHAR2")) {
                colValue = jrs1.getString(j);               
            } else if (dataType.equals("DATE")) {
                colValue = jrs1.getTimestamp(j);
            }
            System.out.println(metadata.getColumnName(j)+ " (" + dataType +"): "+ colValue);            

            Object o = jrs2Collection.stream()
                                     .filter(u -> {
                                         try { 
                                             return (u.getColumnObject(j).equals(colValue));
                                         } catch (Exception e) {
                                             e.printStackTrace();
                                             return false;
                                         }
                                     }) 
                                     .collect(Collectors.toCollection(TreeSet::new));

        }
    }
}

请忽略这样一个事实,即lambda表达式的使用在一段时间内,并且不会在每次迭代时重复使用。如果我能解决现在的问题,我会照顾好。

我必须将try-catch添加到过滤器,因为它返回未处理的异常类型SQLException 。添加此try-catch后,我得到一个在封闭范围内定义的局部变量j必须是u.getColumnObject(j)上的最终或有效最终

我不知道我在做什么是最好的方法,或者我做错了什么(我的同事中有两位看过我的代码,也不知道如何解决这个问题)。

我很感激有关此的任何意见。

1 个答案:

答案 0 :(得分:2)

当你在循环中创建集合而不使用它们时,你不清楚你正在尝试做什么。所以我不能告诉你是否有更好的解决方案。

关于错误,错误消息非常清楚。您不能在lambda中使用可变局部变量。但是,解决方案非常简单:您可以将可变变量的内容分配给不可变变量:

    for (int j = 1; j <= metadata.getColumnCount(); j++) {
        // …
        int currentJ = j;
        Object currentColValue = colValue;
        Object o = jrs2Collection.stream()
          .filter(u -> {
                try { 
                    return (u.getColumnObject(currentJ).equals(currentColValue)); 
                } catch (Exception e) {
                    e.printStackTrace();
                    return false;
                }
            }
        ) 
        .collect(Collectors.toCollection(TreeSet::new));
    }

请注意,currentJcurrentColValue 实际上是最终的,这意味着您可以在不更改程序的情况下向其添加final修饰符。要求在lambda表达式中使用的局部变量是final有效的最终


顺便说一下,不要考虑“在迭代之间重用lambda”。在大多数情况下,JRE将尽可能重用为lambda表达式创建的实例。并且JDBC操作总是超过为lambda表达式创建的临时对象所施加的任何开销。