草庐IT

java - 如何将方法的返回类型声明为传递给方法的数组中最后一个 lambda 的返回类型

coder 2024-03-29 原文

我提出一些我认为不可能的问题,如果是,我会删除问题。

我有方法:

public Object convertBy(Function... functions) {
}

这些函数是:

interface FLines extends Function {
    @Override
    default Object apply(Object t) {
        return null;
    };

    public List<String> getLines(String fileName);
}

interface Join extends Function {
    @Override
    default Object apply(Object t) {
        return null;
    };

    public String join(List<String> lines);//lines to join
}

interface CollectInts extends Function {
    @Override
    default Object apply(Object t) {
        return null;
    };

    public List<Integer> collectInts(String s);
}

interface Sum<T, R> extends Function<T, R> {
    @Override
    default Object apply(Object t) {
        return null;
    };

    public R sum(T list);//list of Integers
}

这些接口(interface)中的抽象方法返回不同类型的值。我将 lambda 传递给我的 convertBy 方法。

我想将 convertBy 的返回类型设置为与 functions[functions.length - 1] 的返回类型相同。

这可能吗?


编辑:

我已经更改了方法的签名和接口(interface)内部方法的签名。它有效,但前提是我确实在下面主要发布的标记位置进行了转换。它只需要在 4 个方法调用中的 3 个中进行强制转换,我想在 main 中完全摆脱强制转换。

import java.util.List;
import java.util.function.Function;


public class InputConverter<T> {

    private T value;

    public InputConverter(T value) {
        this.value = value;
    }


    public <T, R> R convertBy(Function<T, R> special, Function... functions) { 
        if (functions.length == 0) {
            FLines flines = (FLines) special;
            return (R) flines.getLines((value instanceof String) ? (String) value : null);
        } else if (functions.length == 1) {
            FLines flines = (FLines) functions[0];
            Join join = (Join) special;
            return (R) join.join(flines.getLines((String) value));
        } else if (functions.length == 2) {
            if (functions[0] instanceof FLines) {
                FLines flines = (FLines) functions[0];
                Join join = (Join) functions[1];
                CollectInts collectInts = (CollectInts) special;
                return (R) collectInts.collectInts(join.join(flines.getLines((String) value)));
            } else {
                Join join = (Join) functions[0];
                CollectInts collectInts = (CollectInts) functions[1];
                Sum sum = (Sum) special;
                return (R) sum.sum(collectInts.collectInts(join.join((List<String>) value)));
            }
        } else {
            FLines flines = (FLines) functions[0];
            Join join = (Join) functions[1];
            CollectInts collectInts = (CollectInts) functions[2];
            Sum sum = (Sum) special;
            return (R) sum.sum(collectInts.collectInts(join.join(flines.getLines((String) value))));
        }
    }

    /*  public Integer convertBy(Join join, CollectInts collectInts, Sum sum) {
            return sum.sum(collectInts.collectInts(join.join((List<String>) value)));
        }*/

}

interface FLines<T, R> extends Function {
    @Override
    default Object apply(Object t) {
        return null;
    };
    public R getLines(T fileName);
//  public List<String> getLines(String fileName);
}

interface Join<T,R> extends Function {
    @Override
    default Object apply(Object t) {
        return null;
    };
    public R join(T lines);//lines to join
//  public String join(List<String> lines);//lines to join
}

interface CollectInts<T, R> extends Function {
    @Override
    default Object apply(Object t) {
        return null;
    };
    public R collectInts(T t);
//  public List<Integer> collectInts(String s);
}

interface Sum<T, R> extends Function<T, R> {
    @Override
    default Object apply(Object t) {
        return null;
    };

    public R sum(T list);//list of Integers
}

主要方法:

   FLines<String, List<String>> flines ....

  Join<List<String>, String> join ...
  CollectInts<String, List<Integer>> collectInts ...

    Sum<List<Integer>, Integer> sum ...

String fname =/* System.getProperty("user.home") + "/*/ "LamComFile.txt"; 
InputConverter<String> fileConv = new InputConverter<>(fname);
List<String> lines =  fileConv.convertBy(flines);//cannot cast from Object to List<String>
String text =  fileConv.convertBy( join, flines);//cannot cast from Object to String
List<Integer> ints =   fileConv.convertBy(collectInts,flines, join);//cannot cast from Object to List<Integer>
Integer sumints =  fileConv.convertBy(sum, flines, join, collectInts);//works without cast!

我不明白为什么编译器可以理解 sum 返回的内容,但不推断例如 collectInts 返回的内容。

最佳答案

看来,您对泛型类型层次结构有一些误解。当您想要扩展泛型类型时,您必须对扩展类或接口(interface)的实际类型做出基本决定。您可以指定确切的类型,如

interface StringTransformer extends Function<String,String> {}

(这里我们创建了一个扩展泛型但本身不是泛型的类型)

或者您可以创建一个通用类型,它使用自己的类型参数来指定父类(super class)的实际类型参数:

interface NumberFunc<N extends Number> extends Function<N,N> {}

请注意,我们如何创建一个新的类型参数 N有自己的约束,并使用它来参数化父类(super class),以要求其类型参数与我们的相匹配。

相反,当你声明一个类时

interface FLines<T, R> extends Function

您正在扩展原始 类型 Function并创建新的类型参数 <T, R>这在您的场景中完全没用。

为了留在上面的示例中,您可以将它们实现为

StringTransformer reverse = s -> new StringBuilder(s).reverse().toString();
NumberFunc<Integer> dbl = i -> i*2;

并且由于它们继承了正确类型化的方法,您可以使用它们来组合函数:

Function<String,Integer> f = reverse.andThen(Integer::valueOf).andThen(dbl);
System.out.println(f.apply("1234"));

将此应用到您的场景中,您可以像这样定义接口(interface)

interface FLines extends Function<String,List<String>> {
    @Override default List<String> apply(String fileName) {
        return getLines(fileName);
    }        
    public List<String> getLines(String fileName);
}
interface Join extends Function<List<String>,String> {
    @Override default String apply(List<String> lines) {
        return join(lines);
    }
    public String join(List<String> lines);
}
interface CollectInts extends Function<String,List<Integer>> {
    @Override default List<Integer> apply(String s) {
        return collectInts(s);
    }
    public List<Integer> collectInts(String s);
}
interface Sum extends Function<List<Integer>, Integer> {
    @Override default Integer apply(List<Integer> list) {
        return sum(list);
    }
    public Integer sum(List<Integer> list);
}

并重新设计您的 InputConverter只接受可能是组合函数的一个函数:

public class InputConverter<T> {

    private T value;

    public InputConverter(T value) {
        this.value = value;
    }
    public <R> R convertBy(Function<? super T, ? extends R> f) {
        return f.apply(value);
    }
}

这可以以类型安全的方式使用:

FLines flines = name -> {
    try { return Files.readAllLines(Paths.get(name)); }
    catch(IOException ex) { throw new UncheckedIOException(ex); }
};
Join join = list -> String.join(",", list);
CollectInts collectInts=
    s -> Arrays.stream(s.split(",")).map(Integer::parseInt).collect(Collectors.toList());
Sum sum = l -> l.stream().reduce(0, Integer::sum);

InputConverter<String> fileConv = new InputConverter<>("LamComFile.txt");
List<String> lines = fileConv.convertBy(flines);
String text = fileConv.convertBy(flines.andThen(join));
List<Integer> ints = fileConv.convertBy(flines.andThen(join).andThen(collectInts));
Integer sumints = fileConv.convertBy(
    flines.andThen(join).andThen(collectInts).andThen(sum)
);

关于java - 如何将方法的返回类型声明为传递给方法的数组中最后一个 lambda 的返回类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33298519/

有关java - 如何将方法的返回类型声明为传递给方法的数组中最后一个 lambda 的返回类型的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  5. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  6. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  7. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  8. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  9. Ruby 方法() 方法 - 2

    我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby​​-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco

  10. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

随机推荐