【问题标题】:Java 8: how to use lambda expressions on JoinRowSets?Java 8:如何在 JoinRowSets 上使用 lambda 表达式?
【发布时间】:2014-09-17 14:30:25
【问题描述】:

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

我将 2 个查询的结果存储在 2 个 JoinRowSet 对象上(我必须使用 JoinRowSet,因为稍后我必须将其他查询的结果与这些结果结合起来)。然后,我需要将这两个 JoinRowSets 相交,但我不知道它们“属于”哪个类(我不知道查询是否会返回人员、联系人、部门或任何其他内容)。有人告诉我应该使用 lambda 表达式来执行此操作,但我发现了一些问题。

我已将其中一个JoinRowSet 转换为一个集合(我不知道如何直接在JoinRowSet 上使用lambda 表达式),然后我正在循环其中一个JoinRowSets 并且,对于这个JoinRowSet 的每一列,我想获取初始集合上在该列上具有相同值的记录。但是,由于我不知道数据的类别,所以我无法执行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 后,我在 u.getColumnObject(j) 上得到一个 在封闭范围中定义的局部变量 j 必须是最终的或有效的最终

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

如果您对此提供任何意见,我将不胜感激。

【问题讨论】:

    标签: java lambda java-8


    【解决方案1】:

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

    关于错误,错误信息很清楚。你不能在 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 表达式创建的临时对象所带来的任何开销。

    【讨论】:

    • 谢谢。问题解决了。顺便说一句,我想做的只是检索 jrs1 和 jrs2 上的记录。我希望这是正确的方法。
    猜你喜欢
    • 1970-01-01
    • 2017-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-17
    • 2014-06-30
    • 1970-01-01
    • 2018-06-07
    相关资源
    最近更新 更多