接口方法引用到一个函数接口

huangapple go评论86阅读模式
英文:

Interface method reference to a functional interface

问题

我正在使用Java Spring框架和JWT - Java Web Tokens。我有下面的类。

import java.util.function.Function;

import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;

import app.com.javainuse.config.JwtTokenUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;

public class Test {
    public static void main(String[] args) {
        User u = new User("javainuse", "$2a$10$slYQmyNdGzTn7ZLBXBChFOC9f6kFjAqPhccnP6DxlWXx2lPk1C3G6", new ArrayList<>());
        UserDetails ud = u;

        JwtTokenUtil jwtTokenUtil = new JwtTokenUtil();

        String token = jwtTokenUtil.generateToken(ud);
        Test t = new Test();
        System.out.println(t.getClaimFromToken(token, Claims::getSubject));

    }

    public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = getAllClaimsFromToken(token);
        System.out.println(claims.toString());
        return claimsResolver.apply(claims);
    }

    private Claims getAllClaimsFromToken(String token) {
        return Jwts.parser().setSigningKey("javainuse").parseClaimsJws(token).getBody();
    }
}

我无法理解主方法中包含Claims::getSubject的语句。它传递给一个名为Function<Claims, T>的函数接口。如何在getClaimFromToken方法中获取主题值,而getSubject方法没有实现体?当我们将方法引用传递给函数接口时,该方法必须有方法体,但Claims是一个接口,getSubject没有方法体,那么claimsResolver.apply(claims);如何获取主题值?

Note: The provided Java code contains HTML-encoded characters (e.g., &quot;) and angle brackets (< and >) that are not part of the translation. If you want them to be translated as well, please let me know.

英文:

I am working with Java Spring framework and JWT - Java Web Tokens. I have below class

import java.util.function.Function;

import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;

import app.com.javainuse.config.JwtTokenUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;


public class Test {
	public static void main(String[] args) {
		User u=new User(&quot;javainuse&quot;, &quot;$2a$10$slYQmyNdGzTn7ZLBXBChFOC9f6kFjAqPhccnP6DxlWXx2lPk1C3G6&quot;,new ArrayList&lt;&gt;());
		UserDetails ud=u;
		
		JwtTokenUtil jwtTokenUtil=new JwtTokenUtil();
		
		String token = jwtTokenUtil.generateToken(ud);
		Test t=new Test();
		System.out.println(t.getClaimFromToken(token, Claims::getSubject));

		
	}
	
	public &lt;T&gt; T getClaimFromToken(String token, Function&lt;Claims, T&gt; claimsResolver) {
		final Claims claims = getAllClaimsFromToken(token);
		System.out.println(claims.toString());		
		return claimsResolver.apply(claims);
	}

	private Claims getAllClaimsFromToken(String token) {
		return Jwts.parser().setSigningKey(&quot;javainuse&quot;).parseClaimsJws(token).getBody();
	}
}

I am not able to understand statement containing this Claims::getSubject in main method. It gets passed to a functional interface Named Function<Claims,T> claimresolver. How does a method reference getSubject without implementation able to return subject from claims object in getClaimFromToken method ? When we pass method reference to a Functional Interface we the method must have body wight ? but Claims is an interface and getSubject does not have a body then how does "claimsResolver.apply(claims);" is able to get subject value ?

答案1

得分: 1

someInstance.getSubject() 烤了一个蛋糕并将其返回给你。

Claims::getSubject 是烤蛋糕的食谱。

一个执行操作,另一个不执行任何操作,它仅仅是关于如何执行操作的描述 - 无论你将它交给的东西是否执行操作,或者执行多次操作 - 或者将食谱传递给其他人,然后他们面临相同的选择。他们可以做任何他们喜欢的事情:

  • 将食谱扔进垃圾桶(蛋糕将永远不存在)。
  • 烤一个蛋糕。
  • 烤一万个蛋糕。
  • 启动 100 个线程并同时烤 100 个蛋糕。
  • 保存食谱以便以后烤一些蛋糕。

当我写下制作蛋糕的食谱时,我将提到你需要新鲜水。

这意味着,要烤蛋糕,我需要新鲜水。或者也许需要水龙头(能够为我提供新鲜水的东西)。然而,要制作蛋糕的食谱,我根本不需要新鲜水。我只需要告诉你(将会按照我的食谱来烤蛋糕的人):“你需要获取一些新鲜水。我不关心你如何做到这一点!”。

换句话说,蛋糕的食谱是将新鲜水(以及其他一些东西)转化为蛋糕的食谱。它不解释如何获取新鲜水,制作蛋糕的食谱也不附带一瓶新鲜水。

同样地,Claims::getSubject 是一个解释如何将实现 Claims 接口的类的任何实例(即 Claims 实例)转化为字符串的食谱。它不附带 Claims 实例,也不解释如何创建 Claims 实例。它只是说:如果你有一个 Claims 实例,这个食谱可以让你将那个 Claims 转化为一个字符串!

Claims::getSubject 具体说:拿到你的声明,称之为 c。运行 c.getSubject()。嘿,这就是你的字符串。

在这里,你将这个概念(将声明转化为字符串的食谱)传递给 getClaimFromToken 方法,它显然知道如何生成一个实现 Claims 接口的实例。

这就像我今天给你一个蛋糕的食谱,然后你明天拿着一个蛋糕出现。这意味着你设法获得了一些新鲜水。我不知道是如何做到的,而且我也不需要关心 - 我可以享受一些蛋糕!

注意:显然 getClaimsFromToken 知道如何从令牌生成实现 Claims 的实例,然后应用你的食谱(即,在其上调用 .getSubject())。但这只是“猜测” - API 的目的是承诺它会执行 X 操作。你不需要关心它如何执行,只需要关心它做什么,也许确定该库是否适合你的需求,并且它是否按照文档中所说的去做。

英文:

someInstance.getSubject() bakes a cake and returns it to you.

Claims::getSubject is a recipe for baking cakes.

One does the thing. The other doesn't do anything, it merely is a description of how to do the thing - whatever you hand it to can do the thing, or not, or do it 10 times - or pass the recipe on to somebody else who is then faced with the same choice. They can do whatever they like:

  • Toss the recipe in the garbage (and no cakes ever exist).
  • Bake a cake.
  • Bake 10,000 cakes.
  • Start 100 threads and bake 100 cakes simultaneously.
  • Save the recipe for later and bake some cakes tomorrow.

When I write down a recipe for making cake, one of the ingredients I'm going to mention is that you will need fresh water.

That means, to bake a cake, I need fresh water. Or perhaps a tap (something that can make fresh water for me). However, to make a cake recipe I do not need fresh water at all. I just need to tell you (the one who will be following my recipe to bake that cake): "You will need to obtain some fresh water. Not my problem how you do that!".

In other words, a cake recipe is a recipe that turns fresh water (and some other things) into a cake. It does not explain how to obtain fresh water, nor does a recipe for making cake come wrapped around a bottle of fresh water.

In the same vein, Claims::getSubject is a recipe that explains how to turn any instance of a class that implements Claims (i.e. a Claims instance) into a String. It does not come with an instance of Claims nor does it explain how to make an instance of Claims. It merely says: IF you have an instance of Claims, this recipe lets you turn that Claims into a String!

Claims::getSubject specifically says: Take your claims, call it c. Run c.getSubject(). Voila, there's your string.

Here, you pass that notion (a recipe for turning claims into strings) to the getClaimFromToken method, which apparently knows how to produce an instance of Claims.

That's analogous to me handing you a cake recipe today and you showing up with a cake tomorrow. That implies you managed to obtain some fresh water. I do not know how and I don't really need to care - I get to enjoy some cake!

NB: Obviously getClaimsFromToken knows how to make an instance that implements Claims from a token, and will then apply your recipe (i.e., call .getSubject() on it). But that's just 'guessing' - the point of APIs is that they promise they do X. You don't need to bother with knowing how it does it, you just need to bother with knowing what it does, and perhaps ascertaining that the library is fit for purpose and it does what its docs say it does.

答案2

得分: 0

你说得对,这里的Claims::getSubject语法是将一个方法引用传递给Function接口,而不是实现完整的Lambda表达式。

这是如何工作的关键是Claims是一个接口,它扩展了io.jsonwebtoken库中的Claims接口。

io.jsonwebtoken.Claims接口定义了各种getter方法,比如getSubject()getIssuer()等,但没有提供实现。

所以当我们调用:

Claims::getSubject

我们提供了一个引用,指向io.jsonwebtoken.Claims接口上的getSubject()方法。

尽管接口没有提供实现,但在运行时,claims对象实际上将是实现了io.jsonwebtoken.Claims接口并提供了getSubject()具体实现的某个类的实例。

当调用claimsResolver.apply(claims)时,它将调用claims实例上的底层getSubject()方法,该方法返回主题值。

所以总结一下:

  • Claims::getSubject提供了接口方法的引用
  • claims对象提供了该接口的实现
  • 因此,claimsResolver.apply(claims)能够调用实现的getSubject()方法以返回值。
英文:

You're right that the Claims::getSubject syntax here is passing a method reference to the Function interface, rather than implementing the full lambda expression.

The key to how this works is that Claims is an interface that extends the Claims interface from the io.jsonwebtoken library.

That io.jsonwebtoken.Claims interface defines various getter methods like getSubject(), getIssuer() etc. without providing implementations.

So when we call:

Claims::getSubject

We are providing a reference to the getSubject() method on the io.jsonwebtoken.Claims interface.

Even though the interface doesn't provide an implementation, at runtime the claims object will actually be an instance of some class that implements the io.jsonwebtoken.Claims interface and provides a concrete implementation of getSubject().

When claimsResolver.apply(claims) is called, it will invoke that underlying getSubject() method on the claims instance, which returns the subject value.

So in summary:

  • Claims::getSubject provides a reference to the interface method
  • The claims object provides an implementation of that interface
  • So claimsResolver.apply(claims) is able to call the implemented getSubject() method to return the value

答案3

得分: 0

我找到了它在Java中的称呼。它被称为"未绑定的非静态方法引用"。以下是一个链接,解释了每种类型的方法引用以及我要求解释的情景。未绑定的非静态方法引用

英文:

I found what it is called in java. It is called unbound non-static method references. Here is a link which explains every type method references and the scenario which I was asking to explain. Unbound Non static method references

huangapple
  • 本文由 发表于 2023年7月17日 19:30:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/76704019.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定